我试图编写一个示例代码来实现共享指针[仅用于练习]。 在以下示例中,
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;
}
,结果是段错误。
答案 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;
}
注意:虽然这至少修复了一些基本设计,但它仍然缺乏可用性。它缺少取消引用操作符,因此您无法使用指针获取它指向的值。它将在多线程环境中完全破解。我没有想到足够的确定,但我的直接猜测是它也可能不是例外安全。