패스

2011-01-20 7 views
1

내가 그패스

class Base 
{ 
//some implementation 
}; 

class Deriv: public Base 
{ 
//implementation 
} 

class Case1 
{ 
    boost::scoped_ptr<A> a_ //polymorphic data member owned by C 
public: 
    Case1(A* a):a_(a) 
    { 

    } 
}; 
class Case2 
{ 
    boost::scoped_ptr<A> a_ //polymorphic data member owned by C 
public: 
    Case2(std::auto_ptr<A> a):a_(a.release()) 
    { 

    } 
}; 

같은 다형성 클래스 구조를 가지고 있고 제 3 클래스를 가지고 말할 수 있습니다 케이스 가구 1 위에서 설명한 다형성 객체의 하나 소유/2. 이제 Base/Deriv 객체에 대한 포인터를이 객체의 소유권을 취하는 case1/2 클래스의 생성자에 전달해야합니다. 예를 들어이 객체를 스마트 포인터로 전달해야합니까? auto_ptr은 그것이 내가이 개체의 치료를 쳐있어 명확하게, 또는 원시 포인터 (사례 1)과 같은 매우 간단한 구문을 허용 할 수

당신은 스마트 포인터를 전달해야
Case1 c(new Deriv); 
//compared to 
Case2 c(std::auto_ptr<Base>(new Deriv)); 

답변

3

당신은 스마트 것으로 이름을 지정해야합니다 포인터 (예를 들면, 그것은 일시적 일 수 없음) : 첫 번째 예를 들어, Case1 c(new Deriv);에서

std::auto_ptr<Base> p(new Deriv); 
Case2 c(p); // this constructor would need to take the `auto_ptr` by reference 
      // so that it can steal ownership. 

예외가 new Deriv이 실행되고 Case1 개체의 소유권을 때시 사이에 발생하는 경우, 오브젝트가 유출 될 수있다 그것의 생성자에서.

스마트 포인터의 이름을 지정하지 않은 두 번째 예제에서는 일부 상황에서 개체가 유출 될 수 있습니다. 특히,이 문제는 if you have more than one argument to a function에서 발생할 수 있습니다.

+0

사이에 정확히 0 코드가 있음을 의미합니까? 나는 또한 그것이 일시적 일 수없는 이유도 모르겠다. – Puppy

+0

@DeadMG : 사이에 0 코드 어디? 'Case1' 생성자가 원시 포인터 인수를 스마트 포인터에 할당하기 전에 예외를 throw 할 수있는 작업을 수행하면 객체가 유출됩니다. 주제에 대한 Herb Sutter의 GOTW 기사 링크를 추가했습니다. 생성자가 단 하나의 인수 만 취하는 경우에는 문제가되지 않지만 Boost 지침을 비롯한 대부분의 올바른 코딩 스타일에서는 이러한 이유로 모든 스마트 포인터의 이름을 지정하는 것이 좋습니다. –

+0

@James : 그가 Case1 c (new Deriv)를 호출하면 첫 번째 Deriv가 생성되고 Case1이 소유권을 갖습니다. 중간에 던져 질 수있는 코드가 없습니다. 편집 : 그 허점은 C++ 98에 대해 이야기하고 있습니다.내가 아는 한 주로이 결함을 수정하기 위해 존재했던 C++ 03에 여전히 존재한다는 것을 증명하는 또 다른 기사를 찾아야 할 것입니다. – Puppy

0

클래스가 전달 된 객체를 완전히 소유하고 있다면 해당하는 모든 경우에 auto_ptr을 사용하여 클래스를 명시 적으로 만드는 것이 가장 좋습니다. 명시 적으로 auto_ptr을 생성하는 것이 가장 좋은 경우입니다. 이는 API 사용자가 해당 객체를 소유하고 소유권 혼란 가능성을 줄임을 알기 때문입니다.

클래스에 가변적 인 소유권이 있다면 일반적으로 원시 포인터와 소멸 함수를 제공하는 것입니다.

class best_practices { 
    std::function<void(A*)> destructor; 
    A* ptr; 
public: 
    best_practices(A* a, std::function<void(A*)> destructfunc) 
     : ptr(a), destructor(destructfunc) {} 
    ~best_practices() { 
     destructor(ptr); 
    } 
}; 
+0

당신의 예제 코드는 제가 제 대답에서 묘사 한 문제를 보여주고 있습니다 :'std :: function '의 복사 생성자는 예외를 throw 할 수 있습니다 (동적 할당이 실패 할 수도 있음). 그것이 던지면, 당신은 생성자에 전달 된'A' 객체를 유출했습니다. –

+0

(단지 접선 방향으로 관련된 메모에서 예제 클래스에 복사 생성자 및 복사 할당 연산자가 없습니다.) –

+0

동적 할당이 실패하면 누출 된 개체보다 훨씬 큰 문제가 발생합니다. – Puppy

0

나는 이것이 가장 좋은 방법 인을위한 소스를 필요는 없지만, 어떤 방법으로 자원을 저장하는 거라면 일반적으로, 나는 그것이 같은 방법으로 해당 자원을 확보하는 것이 가장 좋습니다 찾을 수 있습니다.

struct store_string 
{ 
    store_string(std::string s) : // potentially free, copy if not 
    s(std::move(s)) // free 
    {} 

    std::string s; 
}; 

또는 C의 +에 :

그 이유는 C++ 0X에 복사/이동이 인수가 주어 졌을 때 이루어집니다, 당신은 단지 같은 스토리지로 이동한다는 것입니다 +03은, 당신의 유형은 싸게 구성 기본적 할 수있는 경우 :

struct store_string 
{ 
    store_string(std::string ss) // make necessary copy 
    { 
     s.swap(ss); // free 
    } 

    std::string s; 
}; 

그래서 당신을 위해, 내가 할 것 :

class Case2 
{ 
    boost::scoped_ptr<A> a_ //polymorphic data member owned by C 
public: 
    Case2(boost::scoped_ptr<A>& aa) 
    { 
     a.swap(aa); // take resource 
    } 
}; 

이 일을하게 당신을 위해 간단하고, 클라이언트가 자원이 어떻게 관리 될지 정확히 알게합니다.