析构函数在STL的共享指针中调用了两次

时间:2018-01-13 19:06:40

标签: c++ stl set shared-ptr

// I developed my own shared pointer . I know it is not required to create 
//ur own when already there is a tested one available . But this is purely 
//for learning, understanding and thinking purpose . The below shared 
//pointer works fine in most of the cases and not causing any memory leak 
//either . But it is not working in case of STL's . Below is my shared 
//pointer .

#include <iostream>
#include <set>
#include <algorithm>
using namespace std;

template <class T>
class SharedPointer
{

    template<class U>
    friend class SharedPointer;

    T *p;
    int *rc;

    public:

    SharedPointer():p(NULL),rc(NULL)   {}

    template <class U>
    explicit SharedPointer(U *q)
    {
        p = static_cast<T *>(q);
        rc = new int();
        ++*rc;
    }

    ~SharedPointer()
    {
        if(rc != NULL && --*rc == 0)
        {
             delete p;
             p = NULL;
             delete rc;
             rc = NULL;
        }
    }

    T * operator -> () { return p; }
    T & operator * () { return *p; }

    template<class U>
    explicit SharedPointer(const SharedPointer<U> &q)
    {
        if(q.p)
        {
           p = static_cast<U *>(q.get());
           rc = q.rc;
           ++*rc;
        }
    }

    template<class U>
    SharedPointer<T> & operator = (const SharedPointer<U> &sp)
    {
        if(this->p != static_cast<T *>(const_cast<U *>(sp.get())))
        {
            if(p != NULL)
            {
                if(--*rc == 0)
                {
                    delete p;
                    delete rc;
                    p = NULL;
                    rc = NULL;
                }
            }
            if(sp.get())
            {
                p = static_cast<T *>(sp.get());
                rc = sp.rc;
                ++*rc;
            }
            else
            {
                p = NULL;
                rc = NULL;
            }
        }
        return *this;
    }
};
// And now below is the usage .
class A
{
    int i;
    public:
    A(int pi):i(pi){  }
    ~A() 
    {
        cout<<"Destructor Called for "<<i<<endl;
    }
    void show()
    {
        cout<<i<<endl;
    }
    int intake()   {  return i;   }
};
struct A_Comp
{
    bool operator()(const SharedPointer<A> &lhs, const SharedPointer<A> &rhs)
    {
        return lhs->intake() < rhs->intake();
    }
};
int main()
{
    set<SharedPointer<A>,A_Comp> myset;
    A * a = new A(30);
    myset.insert(SharedPointer<A>(a));   //   Line X
    set<SharedPointer<A> >::iterator itr;
    for(itr = myset.begin(); itr != myset.end(); itr++)
    {
       (*itr)->show();
    }
    return 0;
}

输出:

析构函数调用30

4151280

实际上究竟发生的是,X行(见注释)正在执行,它正在调用显式的SharedPointer(U * q),这是预期的,但是当这个构造函数完成时,SharedPointer的析构函数被调用了正在删除该变量。因此,即将到来的第二行是垃圾值,它可能在不同的执行中有所不同。我的问题是,为什么只在主函数的return语句之前执行它才会调用~AsredPointer。虽然在返回main之前调用了〜SharedPointer但是我无法弄清楚它为什么第一次被调用。标准shared_ptr没有此行为。

我正在使用-fpermissive选项来避免与const相关的错误。

1 个答案:

答案 0 :(得分:0)

SharedPointer具有隐式编译器生成的复制构造函数和复制赋值运算符,它们执行简单的成员复制并且不维护引用计数。这是在Line X调用的复制构造函数(在你的模板化构造函数中放置一个断点或打印一些东西 - 你会发现它永远不会被调用)。

模板构造函数永远不是复制构造函数,因此不会阻止隐式声明的复制构造函数。您需要添加SharedPointer(const SharedPointer&)构造函数。