C ++ SmartPointers течет при самостоятельном назначении? - PullRequest
1 голос
/ 03 декабря 2009

У меня небольшая проблема с пониманием того, почему мой класс умных указателей просачивается при самообучении. Если я сделаю что-то вроде этого

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;
    }
};

Ответы [ 6 ]

3 голосов
/ 03 декабря 2009
SmartPtr& operator=(SmartPtr& other)
    {
        if(rVar.refCnt != refCnt)

должно быть:

    if ( this != & other ) 
2 голосов
/ 03 декабря 2009

Возможно, вы захотите взглянуть на следующую цитату из Предложение по добавлению интеллектуальных указателей общего назначения в технический отчет библиотеки :

Разработчики Boost обнаружили, что умный указатель совместного владения чрезвычайно труден для правильной реализации. Другие сделали то же самое наблюдение. Например, Скотт Мейерс [Meyers01] говорит:

"Сам STL не содержит интеллектуального указателя для подсчета ссылок, и написание хорошего - того, который работает правильно все время - достаточно сложно, чтобы вы не захотели это делать, если не обязаны. Я опубликовал код для интеллектуального указателя с подсчетом ссылок в More Effective C ++ в 1996 году, и, несмотря на то, что он основывался на устоявшихся реализациях интеллектуальных указателей и подвергался тщательному предварительному обзору, подготовленному опытными разработчиками, в течение многих лет проводился небольшой парад достоверных отчетов об ошибках. замечательно количество хитрых способов, с помощью которых умные указатели подсчета ссылок могут потерпеть неудачу. "

Если это домашняя работа, прочитайте о том, как реализовать оператор копирования и оператор присваивания, используя функцию swap() (member). В противном случае не пытайтесь написать свой умный указатель. Вы не можете выиграть .

1 голос
/ 03 декабря 2009

Я также не вижу утечки, но я думаю, что есть некоторые другие проблемы (кроме многих ошибок компилятора - это не может быть код, который вы используете):

SmartPtr& operator=(SmartPtr& other)

должен принимать аргумент по константной ссылке. Вам не нужно увеличивать счетчик ссылок других, потому что вы можете сделать это с неконстантной левой стороны, поскольку они будут использовать один и тот же экземпляр счетчика ссылок.

Далее, канонический способ реализации присваивания для таких классов - это использование идиома копирования и обмена , что означает, что вы также должны определить тривиальный метод обмена (который просто меняет указатели) и беспокоиться меньше о самостоятельном назначении:)

0 голосов
/ 04 декабря 2009

Практически у любого умного указателя будут случаи, когда он протекает. Так и должно быть, если вы реализуете его, используя ссылки. Есть еще миллион других проблем плюс они медленные. Так как они более ошибочны, чем необработанные указатели, на самом деле не так уж много пользы, если все, что вы получите от этого, это подсчет ссылок. У меня был соблазн использовать их для каких-то очень специальных целей, но они не предназначены для общего программирования. Например, они запрещены в контейнерах STL.

0 голосов
/ 03 декабря 2009

Ваш код не компилируется, поэтому я считаю, что версия, которую вы разместили, не может быть той версией, на которую жалуются ваши коллеги.

0 голосов
/ 03 декабря 2009

У меня сложилось впечатление, что утечки памяти нет. Чтобы быть уверенным:

  • тест с Valgrind или VS-альтернатива
  • используйте std :: tr1 :: shared_ptr (если это больше, чем образовательный)
...