2010-07-16 5 views
0

그래서 나는이 같은 클래스가 있다고 가정 :C++ 포인터 데이터 멤버 : 누가 삭제해야합니까?

사람이 같은 생성자를 사용하는 경우
class A { 
    public: 
     A(SomeHugeClass* huge_object) 
      : m_huge_object(huge_object) {} 
    private: 
     SomeHugeClass* m_huge_object;   
}; 

:

A* foo = new A(new SomeHugeClass()); 

누구의 책임은 생성자에서 newed 개체에 삭제를 호출하는 것입니다? 이 경우 SomeHugeClass가 익명이므로 A 생성자가 호출 된 범위는 foo 만 삭제할 수 있습니다.

그러나 누군가 이러한 생성자를 사용한다면 어떻게 될까요?

SomeHugeClass* hugeObj = new SomeHugeClass(); 
A* foo = new A(hugeObj); 

그런 다음 호출자는 거시 오 삭제를 특정 시점에서 호출 할 수 있습니까?

파괴시 누수 메모리가 구현됩니까?

저는 많은 방법으로이 작업을 수행하는 프로젝트에서 작업하고 있습니다. 스마트 포인터를 사용하기를 좋아하기 때문에 이전 코드를 사용하여 이전 코드를 활용하는 방법에 대해 이야기해야합니다. 저 할 수 있어요.

+0

마지막 코드 스 니펫에서'hugeObj'를 초기화해야합니다. 그렇지 않으면'foo'를 사용할 때 언젠가는 정의되지 않은 동작을 할 수 있습니다. – Gorpik

+0

^잘 잡습니다. 편집 중. – RyanG

+1

아무도 귀하의 경우 포인터 멤버를 삭제해야하는 사람을 말할 수 없습니다. 우리는 신뢰할 수있는 대답을하기위한 상황이 부족합니다. 나는 그것이 당신의 수업이 무엇이고 그것이 무엇을 대표하는지에 달려 있다고 생각합니다. 그것은 어떤 외부 데이터를 참조하는 클래스 일 수 있으며 그의 문서는 수명이 참조 된 데이터의 수명을 초과해서는 안된다는 것을 지정합니다. 아니면 소유권을 가질 수 있습니다. – ereOn

답변

5

: new를 호출하는 일뿐만 아니라 delete를 호출해야합니다. 그렇지 않으면 코드가 너무 지저분 해져서 삭제 된 항목과 삭제 된 항목을 추적 할 수 없습니다.

A :: A가 포인터를 받으면 삭제하지 말아야합니다. 이 간단한 경우를 생각해 :

SomeHugeClass* hugeObj = new SomeHugeClass(); 
A * a1 = new A(hugeObj); 
A * a2 = new A(hugeObj); 

클래스 A가 포인터를 사용하는 다른을 모르는 수 있습니다!

클래스 A가 포인터를 처리하도록하려면 포인터 자체를 만들어야합니다.

은 물론, 당신은 두 경우 모두 처리 할 수 ​​있지만,이 같은 잔인한, 뭔가 수 있습니다 :

A::A() : own_huge_object(true) { 
    m_huge_object = new SomeHugeClass(); 
} 
A::A(SomeHugeClass * huge_object) : own_huge_object(false) { 
    m_huge_object = huge_object; 
} 
A::~A() { if(own_huge_object) delete m_huge_object; } 
+1

+1은 "새 전화를 걸면 전화를해야합니다."라고 표시됩니다. 나는 이것이 물건을 더 우아하게 만든다고 생각한다. 그러나, 나는'Qt'가이 규칙을 존중하지 않는다는 것을 인정해야한다. 그러나 그것을 꽤 잘 다룬다. – ereOn

+0

이 규칙을 일관되게 따르면, 우리는'auto_ptr'을 버려야 할 것입니다! 나는 이것이 타당성이 있지만 너무 멀다고 주장한다. 경우에 따라 소유권을 이전하려고합니다. –

2

호출자는 huge_object을 삭제해야합니다. 생성자가 예외를 throw하고 A의 소멸자가 호출되지 않을 수 있기 때문입니다. 아무도 delete을 호출하지 않기 때문에 구현시 메모리 누수가 발생합니다. 다음과 같이

당신은 shared_ptr을 사용할 수

class A { 
    public: 
     A(shared_ptr<SomeHugeClass> huge_object) 
      : m_huge_object(huge_object) {} 
    private: 
     shared_ptr<SomeHugeClass> m_huge_object;   
}; 

당신이 SomeHugeClass 삭제에 대해 신경 안이 경우. 메모리 누수가 발생할 수

A* foo = new A(new SomeHugeClass()); 

하지 아래에이 줄을 위해서는

+1

누구의 책임인지에 관해서는 동의하지 않지만 스마트 포인터를 사용하는 것이 최선의 해결책이라는 것에 동의합니다. –

+3

기본적으로'shared_ptr'을 사용하지 마십시오! 공유 된 소유권은 의식적인 결정이어야합니다. C++ 0x에 아직 액세스 할 수없는 경우'std :: unique_ptr' 또는'boost :: scoped_ptr'를 사용하는 것이 좋습니다. –

+0

모든 결정은 의식해야합니다. 인터넷에서 코드를 복사하여 붙여 넣는 것만으로도 좋습니다 (SO부터). 링크를 추가 했으므로 OP는'shared_ptr'에 대해 더 많이 읽을 수 있습니다. –

0

, 당신은 무료로 메모리에 있는지 클래스 A의 소멸자 m_huge_object에 의해 지시 할 수

클래스 A의 정의는 다음과 같습니다.

class A { 
    public: 
    A(SomeHugeClass* huge_object) 
     : m_huge_object(huge_object) {} 
    ~A() { delete m_huge_object; } 
    private: 
    SomeHugeClass* m_huge_object;   
}; 

나는 위의 것에 대해 마음에 들지 않는다. 나는 누구든지 기억을 할당하는 사람이 그 기억을 해방시킬 책임이있는 사람이어야한다는 점을 선호한다. 또한 Kirill이 지적한 문제가 있습니다. 그래서 클래스 A의 당신의 정의를 유지하고, 같은 코드는 간단 할 수있다 : 가능 때마다 나는이 간단한 규칙을 따르도록하려고

SomeHugeClass* hugeObj = new SomeHugeClass(); 
A* foo = new A(hugeObj); 
//some code 
delete hugeObj; 
delete foo; 
+0

좋지 않습니다. 'foo'의 소멸자가'hugeObj'를 참조해야하기 때문에 예외가 발생했을 수 있습니다. –

+0

@Steven Sudit : 어느 것입니까? 두 번째 버전을 사용하는 경우 포스터가 처음에 사용한 코드와 동일합니다. 즉, 소멸자가 없습니다 (이는 내가 말한 것입니다). –

+0

두 번째 버전에서'~ A'는'm_hugeObj'를 삭제하지 않는다고 효과적으로 말했습니다. 그런 다음'foo'가 두 번째로 생성되었지만 'hugeObj'가 *'foo '후에 파괴되었습니다. 이것은 매우 잘못되었습니다. 나는 그것이 틀린 이유의 예를 들었다 :'foo'는'huge_Obj'와 같은 인스턴스를 가리키는'm_hugeObj'를 가지고 있으며,이 포인터를 그것의 전체 수명 동안 사용할 것으로 예상 될 수 있습니다. 그럼에도 불구하고'hugeObj'를 삭제하고'm_hugeObj'가 유효하지 않은 위치를 가리 키도록하여'foo' 아래에서 양탄자를 꺼냅니다. –

0

이것은 더 많은 설계 문제. 전통적으로 const가 아닌 포인터를 생성자에 전달하면 객체가 포인터를 해제해야합니다. 복사본을 보관하려면 const 참조를 전달하십시오. SomeHugeClass는 일반적으로 그 거대한 아니라, 대량의 메모리 소유 (예를 들면 포인터를.) :

대체 디자인이 라인을 따라 뭔가 SomeHugeClass가 효율적으로 구현하는 경우

class A 
{ 
    SomeHugeClass m_; 

public: 
    A(SomeHugeClass x) { m_.swap(x); } 
}; 

이 디자인이 가능을 스왑 (포인터 교환). 생성자는 m_으로 바꾸기 전에 x 복사본을 만들고 생성자에 임시 개체를 전달하면 해당 복사본이 컴파일러에 의해 생략 될 수 있습니다.

SomeHugeClass는 smart_pointer<SomeHugeClass>으로 대체 할 수 있습니다. 임시 식별자이므로 smart_pointer (new SomeHugeClass())를 생성자에 전달할 때 원하는 의미를 부여합니다.

EDIT (명확성을 위해 ...) : 최종 코드는

class A 
{ 
    smart_ptr<SHC> m_; 

public: 
    A(smart_ptr<SHC> x) { m_.swap(x); } 
}; 
당신이 A(new SHC(...)) (NO 복사, A는 파괴됩니다 삭제)를 호출 할 때 필요한 동작을 가지고

, 그리고 때를 같이 보일 수 있습니다 A(smart_ptr<SHC>(a)) (a 사본이 수행되고 A가 소멸되면 해제됩니다).

관련 문제