2009-12-03 2 views
1

나는 스마트 포인터 클래스가 자기 집안에 새어 나가는 이유를 이해하는데 작은 문제가있다. 내가이C++ SmartPointers가 자체 할당에서 유출 되나요?

SmartPtr sp1(new CSine());//CSine is a class that implements IFunction iterface 
sp1=sp1; 

처럼 뭔가를 할 경우 내 동료 내 스마트 포인터 누출 말해 줬어.

SmartPtr sp1(new CSine()); 
->CSine constructor 
->RefCounter increment 0->1 
->RefCounter constructor 
->SmartPtr constructor 

sp1=sp1; 
->checks if this.RefCounter == to parameter.RefCounter, if true returns the smart pointer unmodified else modifies the object and returns it with the new values; in this case it returns true and returns the object unchanged. 

at the end 
->SmartPtr destructor 
->RefCounter decrement 1->0 
->RefCounter destructor 
->CSine destructor 

그들이 생각하는 이유는 이해할 수없는 내 스마트 포인터 누출 ... 어떤 아이디어 : 나는에 가서 테스트 있는지 추적하기 위해 내 스마트 포인터의 일부 로그 메시지를 추가하고이를보고? 미리 감사드립니다.

class SmartPtr 
{ 
private: 
    RefCounter* refCnt; 
    void Clear() 
    { 
     if(!isNull() && refCnt->Decr() == 0) 
      delete refCnt; 
     refCnt = 0; 
    }; 
public: 
    explicit SmartPtr(); 
    explicit SmartPtr(IFunction *pt):refCnt(new RefCounter(pt)){}; 
    SmartPtr(SmartPtr& other) 
    { 
     refCnt = other.refCnt; 
     if (!isNull()) 
      refCnt->Incr(); 
    }; 
    virtual ~SmartPtr(void){Clear();}; 

    SmartPtr& operator=(SmartPtr& other) 
    { 
     if(other.refCnt != refCnt) 
     { 
      if(!rVar.isNull()) 
       other.refCnt->Incr(); 
      Clear(); 
      refCnt = other.refCnt; 
     } 
     return *this; 
    }; 

    SmartPtr& operator=(IFunction* _p) 
    { 

     if(!isNull()) 
     { 
      Clear(); 
     } 
     refCnt = new RefCounter(fct); 
     return *this; 
    }; 

    IFunction* operator->(); 
    const IFunction* operator->() const; 
    IFunction& operator*(); 
    const IFunction& operator*() const; 
    bool isNull() const { return refCnt == 0; }; 

    inline bool operator==(const int _number) const; 
    inline bool operator!=(const int _number) const; 
    inline bool operator==(IFunction* _other) const; 
    inline bool operator!=(IFunction* _other) const; 
    inline bool operator==(SmartPtr& _other) const; 
    inline bool operator!=(SmartPtr& _other) const; 
}; 

class RefCounter 
{ 
    friend class SmartPtr; 
private: 
    IFunction* p; 
    unsigned c; 

    explicit RefCounter(IFunction* _p):c(0),p(_p) 
    { 
     if(_p != NULL) 
      Incr(); 
     cout<<"RefCounter constructor."<<endl; 
    } 
    virtual ~RefCounter(void) 
    { 
     cout<<"RefCounter destructor."<<endl; 
     if(c == 0) 
      delete p; 
    } 
    unsigned Incr() 
    { 
     ++c; 
     cout<<"RefCounter increment count:"<<c-1<<" to "<<c<<endl; 
     return c; 
    } 
    unsigned Decr() 
    { 
     if(c!=0) 
     { 
      --c; 
      cout<<"RefCounter decrement count:"<<c+1<<" to "<<c<<endl; 
      return c; 
     } 
     else 
      return 0; 
    } 
}; 
+8

왜 스마트 포인터를 쓰고 있습니까? 수년간의 디버깅을 해왔습니다. Boost의'shared_ptr'은 모든 Boost 구성 요소 중에서 가장 많이 수정 된 클래스 중 하나입니다. 올바르게 진행하는 것은 매우 까다로운 일입니다. – jalf

+0

나는 커튼 뒤에 무슨 일이 일어나고 있는지 어떻게 이해하려고 노력하고있다. –

+0

동료들에게 누출이라고 생각하는 이유를 물어 보았습니까? 그들은 테스트 케이스를 가지고 있습니까? 아니면 애플리케이션에서 누수가 발생했다는보고 만하고 코드가 잘못 될 수는 없다고 비난합니다 .-) –

답변

0

제 기억은 메모리 누수가 없다는 것입니다. 는 확실히 (이 경우 더 교육보다) Valgrind의 또는

  • 사용 VS-대안

    • 테스트 표준 : TR1 :: shared_ptr의
  • 3
    SmartPtr& operator=(SmartPtr& other) 
        { 
         if(rVar.refCnt != refCnt) 
    

    은 다음과 같아야합니다

    if (this != & other) 
    
    +1

    출력이 내 테스트에서와 동일하므로 누출되는 이유는 무엇입니까? 똑같지 않다면 SmartPtr을 받으면 카운트를 늘리고 이전 RefCount를 해제하고 현재 smartPtr에 할당합니다. 동일한 동작이 제안 된대로 수정 된 코드에서 발생합니다. –

    +0

    나는 그것이 누출되는 이유를 모른다. 다른 사람들은 ref 카운트 된 포인터를 쓰는 것이 어렵다는 것을 지적했기 때문에 모든 코드를 읽지 않아도됩니다. 그러나 귀하의 코드는 제목이 귀하의 질문에 대한 제안이었던 자체 할당을 위해 올바르게 검사하지 않습니다. –

    +2

    나는 당신의 코드를 텍스트 편집기에 복사하고 "rVar"를 검색했다. 내가 뭔가를 놓치지 않는 한, 이것은 어디에도 선언되어 있지 않습니다. –

    2

    당신은 A Proposal to Add General Purpose Smart Pointers to the Library Technical Report에서 다음 인용문에서 볼 수도 있습니다 :

    부스트 개발자가 공유 소유권 스마트 포인터가 상당히 어려운 발견 올바르게 구현할 수 있습니다. 다른 사람들도 똑같은 관찰을했습니다. 예를 들어, 스콧 마이어스는 [Meyers01] 말한다 :

    "는 STL 자체에 포함 된 참조 카운팅 스마트 포인터를, 그리고 좋은 기록 없음 - 그렇지 충분히 까다 롭습니다 - 정확하게 모든 시간을 작동 하나 1996 년에 더 효과적인 C++에 레퍼런스 카운팅 스마트 포인터 용 코드를 게시했으며, 스마트 포인터 구현을 기반으로하고 경험이 많은 개발자가 광범위한 발행 전 검토를 제출 했음에도 불구하고 유효한 버그 리포트의 작은 퍼레이드가 수년간 흘렀다. 레퍼런스 카운팅 스마트 포인터가 실패 할 수있는 미묘한 방법의 수가 놀랍다. " 이 숙제 인 경우

    는 복사의 ctor와 swap() (멤버) 함수를 사용하여 할당 연산자를 구현하는 방법에 대해 읽어보십시오. 그렇지 않으면 자신의 스마트 포인터를 작성하지 마십시오. You cannot win.

    0

    귀하의 코드는 컴파일되지 않습니다 , 당신이 게시 한 버전이 동료가 불평하는 버전이 될 수 없다고 믿게 만듭니다.

    1

    나도 누수가 표시되지 않습니다,하지만 난 다른 문제가있는 생각 (많은 컴파일러 오류가 아닌 다른이 -이 사용하는 코드가 될 수 없습니다) :

    SmartPtr& operator=(SmartPtr& other) 
    

    에 의해 인수를 취해야한다 const 참조. 다른 참조 수를 증가시키지 않아도됩니다. 동일한 참조 수 인스턴스를 공유하므로 const가 아닌 왼쪽에서 할 수 있기 때문입니다.

    다음, 사용하는 같은 클래스에 대한 할당을 구현하는 표준 식으로 copy-and-swap idiom - 당신은 또한 (단지 포인터 스왑) 사소한 스왑 방법을 정의하고, 자기 과제 :

    +0

    스마트 포인터의 복사 및 스왑 문제는 그것은 임시 복사에 대한 추가 증가 및 감소를 수행함으로써 할당 비용을 거의 두 배로 늘립니다. ref-counting의 오버 헤드는 그 비용에 관한 것입니다. 특히 thread가 안전하다고 생각되면 (이 구현은 그렇지 않습니다. 따라서 다른 모든 웜이 될 수 있습니다). –

    +0

    추가 감소 및 증가가 없습니다. 당신은 각각 하나를 얻습니다 : 새로운 참조 카운트는 복사 생성자에 의해 한번 증가 될 것이고, 오래된 참조 카운트는 임시의 소멸자에 의해 한 번 감소 될 것입니다. 둘 다 자기 할당의 경우에만 피할 수 있지만 얼마나 자주 발생합니까? (포인터 할당이 더 많아지기 때문에 약간의 오버 헤드가있을 수 있지만 다른 한편으로는 자체 할당 테스트를 생략 할 수 있습니다. 또한 그림과 같이 컴파일러가 인라인하고 트릭을하면 어떻게 될지 확실하지 않습니다. 클래스는 일반적으로 템플릿으로되어 있습니다.) – UncleBens

    +0

    테스트 (OP의 고정 SmartPtr 포함)가 올바른지 확인합니다. 나는 std :: rotate라고 불렀다. 그리고 그 raw 포인터가 ~ 0.8 초 걸렸다. OP 할당은 ~ 1.3 초가 걸리고 copy-swap 할당은 ~ 1.8 초 걸렸다. – UncleBens

    -1
    에 대해 덜 걱정해야 의미

    거의 모든 스마트 포인터는 누출되는 경우가 있습니다. 참조를 사용하여 구현하는 방법 일뿐입니다. 또한 천만 가지 다른 문제와 천천히 있습니다. 원시 포인터보다 버그가 많으므로 그 중 하나에서 벗어나는 것이 참조 계산 인 경우별로 유용하지 않습니다. 나는 아주 특별한 목적을 위해 그것들을 사용하도록 유혹되었지만 일반적인 프로그래밍 용도로 사용하지는 않는다. 예를 들어 STL 컨테이너에 허용되지 않는 이유가 있습니다.

    +0

    스마트 포인터는 분명히 원시 포인터보다 버그가 없습니다. 내 자신의 경험과 여러 전문가들은 boost :: shared_ptr과 같은 좋은 스마트 포인터를 사용하면 메모리 관리를 단순한 순서로 단순화한다는 것을 보여줍니다. STL 컨테이너에서 허용되지 않는 std :: auto_ptr은 좋은 예는 아니지만 표준위원회에서 오류를 인정하고 C++ 0x에서 사용되지 않습니다. – alexk7

    관련 문제