2011-10-30 2 views
0

매개 변수로 객체를 전달하는 좋은 방법은 무엇으로? 필자의 코드에서는 포인터 대신 참조를 사용하고 있으며 가능한 경우이 접근법을 고수하고 싶습니다. 그러나이 제대로 작동하지 않는 하나의 경우가있다 :합격 자원 락 객체 매개 변수

class Resource { 
    Resource(...) { //expensive resource initialization } 
    ~Resource() { //destroy resource } 
}; 

class User { 
    User(const Resource & res) : res_(res) { //initialize user } 
private: 
    Resource res_; 
} 

void Init() { 
    Resource res(...); 
    User user = new User(res); 
} //res is destroyed - along with its associated resource 
//user can no longer use the resource 

이러한 시나리오에서 사용되어야 어떤 모범 사례가 있습니까? 내가 달성하고자하는 결과는 User 객체가 소멸 될 때 자동으로 Resource 파괴가 아니라 Resource 자체를 만들기 위해 User 객체에 의존하는 것입니다. 복사 느낌표가 Resource 인 오버로드해야한다고 생각합니다. 다른 아이디어?

+0

'User' 객체간에'Resource' 객체를 공유하고 싶습니까, 아니면'User' 객체의 외부에 객체를 만들었습니까? – msandiford

+0

나는 그것들을'User' 객체들 사이에서 공유 할 필요가 있습니다. –

+4

디자인에 대해 더 알지 못하는 사이에 툴 체인의 나이에 따라 boost, tr1 또는 C++ 11 표준에서 사용할 수있는 shared_ptr과 같은 것을 원한다고 생각합니다. http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/shared_ptr.htm – msandiford

답변

1

가장 좋은 샷 User 클래스의 shared_ptr<Resource> 멤버를 들고있다. 그러나이를 위해서는 무료 (힙) 메모리에 자원을 생성해야합니다.

class User { 
    User(Resource * res) : res_ptr(res) { //initialize user } 
private: 
    shared_ptr<Resource> res_ptr; 
} 

void Init() { 
    Resource * res = new Resource(...); 
    User user = new User(res); 
} 

두 번째 방법은 Resource에 대해 가짜 복사 생성자와 스왑 메커니즘을 제공하는 것입니다.

class Resource 
{ 
private: 
    explicit Resource(const Resource &); // disabled to avoid heavy copy. 
    const Resource & operator = (const Resource &); 
    int * int_res; 
public: 
    Resource() : int_res(new int(100)) { } 

    ~Resource() 
    { 
    if(int_res != NULL) 
     delete int_res; 
    } 

    Resource(Resource & other) : int_res(NULL) 
    { 
    this->swap(other); 
    } 

    void swap(Resource & other) 
    { 
    using std::swap; 
    swap(int_res, other.int_res); 
    } 
}; 

class User 
{ 
private: 
    Resource resource; 
    User(); 
    User(const User &); 
    const User & operator = (const User &); 
public: 
    User(Resource & res) : resource(res) { } 
    ~User() { } 
}; 

그러나 사용자를 생성 한 후에는 리소스를 좀비 상태로 남겨두기 때문에 위험하고 오류가 발생하기 쉽습니다. 이 코드에서는 NULL에 할당 된 int_res 포인터에 대한 모든 액세스가 액세스 위반 오류를 표시합니다. 내가 설명 할 수

마지막 방법은 "이동 의미의"C++ 0X 기능을 사용하고 있습니다.

class Resource 
{ 
// ... 
// ... 
    // Replace with Resource(Resource & other) 
    Resource(Resource && other) : int_res(NULL) //Move constructor 
    { 
    this->swap(other); 
    } 

    const Resource & operator = (Resource && other) // Move assignment operator 
    { 
     this->swap(other); 
     return *this; 
    } 

    void swap(Resource & other) 
    { 
    using std::swap; 
    swap(int_res, other.int_res); 
    } 
}; 

class User 
{ 
private: 
    Resource resource; 
    User(); 
    User(const User &); 
    const User & operator = (const User &); 
public: 
    User(Resource && res) : resource(std::move(res)) { } 
    ~User() { } 
}; 

void Init() { 
    Resource res(...); 
    User user = new User(std::move(res)); 
} 

이 접근 방법은 다소 안전합니다. 포인터를 다룰 필요가 없으며 std::move을 쓰는 것을 잊어 버린 경우 "Resource 인스턴스를 Resource&&에 바인드 할 수 없습니다"또는 "의 복사 구성자가 비활성화 됨"이라는 컴파일러 오류가 발생합니다.

&& 개체가 일시적 강조하고 증발 것입니다. 따라서이 접근법은 Resource가 함수에 의해 생성되고 반환되는 시나리오에 더 적합합니다. 내가 너라면 나는 생성자를 비공개로 만들고 친구 함수로 생성자를 생성 할 것이다.

Resource GetResource(....) 
{ 
    Resource res(...); 
    return res; 
} 

void Init() 
{  
    User user = new User(GetResource(...)); 
} 

이 코드는 "이동 의미"와 완벽하게 일치합니다. C++ 0x 코드를 작성할 수 있으면 배우셔야합니다. Thisthis은 두 가지 좋은 동영상입니다.

+0

'User (Resource * res) : res_ptr (res)'혼동하지 말고'shared_ptr <> '또는 원시 포인터를 사용하십시오. – ildjarn

+0

@ildjarn :'Resource'에 대한 포인터를 가진'User' 클래스 안에'shared_ptr'을 만들고 있습니다. 이것의 단점은 무엇입니까? –

+0

단점은'Resource'는 원시 포인터의 소유권을 취한다는 것입니다. 이러한 의미는 명백하지 않습니다. 그러나,'Resource'가 미처리 포인터가 아닌'shared_ptr <>'을 사용하면 될 것입니다. – ildjarn

관련 문제