2016-07-15 3 views
1

어쩌면 이것은 바보 같은 질문 일지 모르지만, 나는 단지 물건을 엉망으로 만들고 싶지 않습니다. 나는이 구조체가 있다고 가정 :스마트 포인터없이 이중 삭제를 방지하는 방법은 무엇입니까?

struct Foo{ 
    struct Bar { virtual int calc(int x) = 0; }; 
    Bar* barX; 
    Bar* barY; 
    int x,y; 
    Foo(Bar* bx,Bar* by) : barX(by),barY(by) {} 
    void process(int xx,int yy){ 
     x = barX->calc(xx); 
     y = barY->calc(yy); 
    } 
    ~Foo(); 
}; 

struct IDBar : Foo::Bar { int calc(int x) { return x; } }; 

int main() { 
    IDBar* b = new IDBar(); 
    Foo f = Foo(b,b); 
    Foo f2 = Foo(new IDBar(),new IDBar()); 
} 

나는 C++ 11 (즉, 더 smartpointers)를 사용할 수 없습니다를, 나는 100 % 확실하지 않다 ... 이 모두 (또는 가능 하나를 삭제하는 올바른 방법인가)이 Bar 객체 :

Foo::~Foo(){ 
    if (barX == barY){ delete barX; } 
    else { delete barX; delete barY; } 
} 

?

추 신 : FooBar 개체를 소유하고 있습니다 (그러므로 삭제할 책임이 있습니다). 생성자에 전달 된 Bar은 다른 용도로 사용되지 않아야합니다. 실제로 Bar은 하나의 Foo에만 속할 수 있습니다 (결함은 나중에 만 실현되었지만 지금은 괜찮습니다). 또한 Foo은 복사하지 않아야합니다 (아마도 내가 명시 적으로이를 방지해야합니다).

+2

바를 소유 한 사람은 누구입니까? –

+0

부스트 스마트 포인터는 어떻습니까? – KIIV

+0

@KarolyHorvath Foo가 막대를 소유하고 있습니다. – user463035818

답변

1

Taztingo와 약간의 의견 차이가 있습니다. 객체가 전달 된 리소스의 소유권을 가져 오는 것이 무리가 아닙니다. 이것은 모든 종류의 실제 코드에서 발생합니다. 클래스가 생성자로 전달 된 리소스의 소유권을 가져온다는 사실이 문서화되어 있습니다. 누군가 문서를 보지 않고 클래스를 부적절하게 사용하면 발에서 스스로를 쏘고있는 것입니다.

그러나이 오류는 오류가 발생하기 쉽기 때문에 이러한 종류의 오류를 발견하거나 이러한 오류가 발생하지 않도록하려는 것입니다. Foo이 자원을 소유하고 있다고 생각하는 사람이 아무도 없다고 보장 할 수있는 방법이 있다면, 우리는 앞으로 나아갈 것입니다. C++ 11에서는 std::unique_ptr을 사용하면 쉽습니다. 이전 C++ 표준에는 std::auto_ptr이 있습니다. C++의 이전 표준에는 이동 생성자가 없지만 할당시 또는 std::auto_ptr으로 복사 할 때 이전의 std::auto_ptr에서 리소스를 양도함으로써 마찬가지로 std::auto_ptr의 기능을 수행합니다.

나는 std::auto_ptr을 사용하는 것이 좋습니다.

동일한 리소스가 명시 적으로 클래스 Foo의 두 생성자 매개 변수에 전달되도록 허용되는 경우 std::auto_ptr<Bar> 하나만 허용하는 새 생성자를 만듭니다.

마지막으로 Foo이 복사되지 않도록하려면 복사 생성자와 할당 연산자를 모두 비공개로 선언하십시오.

+0

@ tobi303 : 알다시피, 당신이 좋아하는 대답을 바꿨습니다. 그러나 사용자가 Foo (a, b)와 Foo (b, c) 두 객체를 동시에 사용할 수있는 유스 케이스를 제공하려는 경우 도움이되지 않습니다! – Roland

+0

@Roland 무슨 뜻인지 알 겠어. 그러나이 유스 케이스는 어쨌든 지원되지 않을 것입니다. 왜냐하면'Foo'가 전달 된 포인터의 독점적 소유권을 가지고 있다고 생각하기 때문입니다. 두 개의'Foo'에'b'를 전달하면 두 명의 소유자가 있다는 것을 의미합니다. –

1

아니요 아니요. god no

Foo::~Foo(){ 
     if (barX == barY){ delete barX; } 
     else { delete barX; delete barY; } 
    } 

개체가 자체로 할당하지 않은 메모리를 삭제하는 것은 매우 위험합니다. 이러한 객체를 소유하고있는 객체는 모두 삭제해야합니다. 귀하의 경우에는 메인 할당 된 개체를 삭제 담당 담당해야합니다.

int main() { 
    IDBar* b = new IDBar(); 
    IDBar* b2 = new IDBar(); 
    IDBar* b3 = new IDBar(); 
    Foo f = Foo(b,b); 
    Foo f2 = Foo(b2,b3); 
    delete b; 
    delete b2; 
    delete b3; 
} 

메모리 관리를 처리하는 객체의 완벽한 예는 LinkedList입니다. LinkedList는 자체 내에 노드를 만듭니다. 사용자는 자신에 대해 알지 못하고 대신 T를 삽입합니다. 그러면 LinkedList가 삭제 될 때 삭제됩니다. 사용자는 LinkedList를 작성했기 때문에 LinkedList를 삭제하는 역할 만 담당합니다.

std::list<MyObject*> list; 
MyObject* object = new MyObject; 
list.push_back(object); 
//The list isn't going to delete object because it doesn't own it 
delete object; 
+2

일반적으로 모든 대문자를 쓰는 데 약간의 알레르기가 있습니다. 그렇다고해도 별다른 의미가 없습니다. "NO NO NO ... ". 소유권은 생성자에게'Bar '를 전달한 후'Foo'에 의해 취해 지므로'Foo'는 그 객체를 삭제해야합니다. – user463035818

+0

그러면 Foo가 소유하지 않는 이유는 무엇입니까? – Taztingo

+0

사용자가 어떤 종류의'Bar'를 인스턴스화 할 것인지 선택해야하기 때문에 – user463035818

1

당신이 건축을 주장하고 타지 o의 디자인 규칙에주의를 기울이지 않으면; 그러면 대답은 '예'입니다. 올바른 방법입니다!

그리고 나서 Foo 클래스의 강력한 API 문서를 만들고이 객체의 생성자 인 Bar 객체의 평생 책임을 대신 수행해야합니다.

+0

나는이 대답을 좋아한다. – Taztingo

+0

"규칙"에 유의할 수는 있지만 이해가되지 않습니다. – user463035818

+0

@ tobi303 : Tazingo는 두 개의 객체 Foo (a, b)와 Foo (b, c)를 동시에 인스턴스화 할 수없는 카운터 예제를 작성하므로 강력한 API 설명이 필요합니다. – Roland

1

나는 완벽하다고 생각하지 않는다. 단지 세 포인터가이라고 상상해 보라.

delete이 두 번 나오지 않게하려면 delete 만 전화하면 어떨까요? 시나리오를 고려해보십시오 :

  1. 메모리 풀을 할당하십시오 (천 개의 개체를 할당 할만큼 충분). 이것은 새로운 PoolAllocator<T> 클래스의 어딘가에서 일반적인 new 호출을 통해 힙에 할당되어야하며, 그 desctructor 내에는 delete이 할당되어야합니다.
  2. 풀을 구현하여 T에 사용할 메모리를 반환하는 void* getMemory<T>() 함수를 지원하고 내부 포인터를 전진시킵니다.
  3. T이 무엇이든지 호출되었는지 확인하십시오. 풀의 새 배치를 통해서만 메모리를 제공 할 수 있습니다.

결국 메모리에 대해 걱정할 필요가 없습니다. 풀 객체는 힙에 내부가있는 일반 스택 변수가 될 수 있습니다.

그렇지 않은 경우 proto-smart 포인터를 구현하는 것을 금지합니까?

관련 문제