复制构造函数,模板类没有被调用

时间:2014-02-15 06:26:42

标签: c++ templates copy-constructor

我试图编写一个示例代码来实现共享指针[仅用于练习]。 在以下示例中,

  • 为什么编译器不抱怨修改other_T
  • 为什么没有调用复制构造函数SharedPtr(const T& other_T)? 这是代码段。

    #include <iostream>
    using namespace std;
    #define DBG cout<<"[DEBUG]"<<__PRETTY_FUNCTION__<<endl
    class RefCount
    {
    protected:
        int m_ref;
        RefCount(){ DBG; m_ref = 1 ; }
        void reference(){ DBG; ++m_ref; }
        void dereference(){ DBG;--m_ref;    }
    };
    
     template <class T>
     class SharedPtr : public RefCount
     {
        T* m_T;
     public:
        SharedPtr() {  DBG; m_T = new T; }
        SharedPtr(const T& other_T){
            DBG;
            m_T = other_T.m_T;
            other_T.dereference();
            other_T.m_T = NULL;
        }
        ~SharedPtr() {
            DBG;
            dereference();
           cout<<m_ref<<endl;
           if(m_ref <= 0 && m_T != NULL ){
               cout<<"Destroying"<<endl;
               delete m_T;
               m_T = NULL;
            }
        }
    };
    
    class A{};
    int main()
    {
        SharedPtr<A> obj;
        cout<<"assigning "<<endl;
        SharedPtr<A> obj2 = obj;
        cout<<"END"<<endl;
        return 0;
    }
    

,结果是段错误。

1 个答案:

答案 0 :(得分:0)

您的主要问题是复制构造函数调用 - 但您尚未定义复制构造函数,因此您将获得默认情况下由编译器定义的复制构造函数。 / p>

该复制构造函数只是执行成员复制。这意味着您已使用A分配了一个new,然后将两个SharedPtr对象指向同一个A。第一个被销毁的对象删除A对象。然后第二个被破坏,再次尝试删除同一个对象,然后发生混乱。

最后,它看起来并不像我(任何?),但这会产生任何真正的不同。我很确定你的基本设计已被打破。要获得有效的共享指针,您有一个引用计数和指向最终对象的“原始”指针。然后你有N个SharedPtr对象引用那个引用最终对象的引用计数/指针结构。

您正在尝试将原始指针/引用计数组合到单个SharedPtr中,但我看不到任何可以实际工作的方法。

在我看来,你所谓的RefCount的基本概念实际上是SharedPtr设计的一部分。因此,我认为它的定义应该嵌套在SharedPtr内(并且可能是私有的,因为外界没有理由知道它存在,更不用说能够直接访问它了。)

考虑到这些因素,代码可能最终会出现这样的结果:

#include <iostream>
using namespace std;

#define DBG cout<<"[DEBUG]"<<__PRETTY_FUNCTION__<<endl

template <class T>
class SharedPtr {

    template <class U>
    struct Ref {
        mutable int m_ref;
        U *data;
        Ref(T *data) : m_ref(1), data(data) { DBG; }
        void add_ref() const { DBG; ++m_ref; std::cout << "m_ref=" << m_ref << "\n"; }
        void sub_ref() const { DBG; --m_ref; std::cout << "m_ref=" << m_ref << "\n"; }
        ~Ref() { delete data; }
    };

    Ref<T> *r;
public:
    SharedPtr(T *data) { DBG; r = new Ref<T>(data); }
    SharedPtr(SharedPtr const &p) : r(p.r) { DBG; r->add_ref(); }
    ~SharedPtr() {
        DBG;
        r->sub_ref();
        if (0 == r->m_ref) {
            delete r;
            std::cout << "deleted pointee\n";
        }
    }
};

class A{};

int main() {
    SharedPtr<A> obj(new A);
    cout<<"copying "<<endl;
    SharedPtr<A> obj2 = obj;
    cout<<"END"<<endl;
    return 0;
}

注意:虽然这至少修复了一些基本设计,但它仍然缺乏可用性。它缺少取消引用操作符,因此您无法使用指针获取它指向的值。它将在多线程环境中完全破解。我没有想到足够的确定,但我的直接猜测是它也可能不是例外安全。