C++ 避免对非虚拟析构函数进行对象切片
作为练习,我正在为智能指针编写代码。使用在线教程(,),我开发了一个带有引用计数的普通智能指针类。问题是我无法理解以下几点: 当智能指针检测到不再存在对 对于特定对象,它必须通过指向 原始类型,即使最终智能的模板参数 指针是基类型。这是为了避免对对象进行切片 非虚拟析构函数 我怎样才能做到这一点。基本上我的代码如下所示(来自教程)C++ 避免对非虚拟析构函数进行对象切片,c++,templates,pointers,g++,smart-pointers,C++,Templates,Pointers,G++,Smart Pointers,作为练习,我正在为智能指针编写代码。使用在线教程(,),我开发了一个带有引用计数的普通智能指针类。问题是我无法理解以下几点: 当智能指针检测到不再存在对 对于特定对象,它必须通过指向 原始类型,即使最终智能的模板参数 指针是基类型。这是为了避免对对象进行切片 非虚拟析构函数 我怎样才能做到这一点。基本上我的代码如下所示(来自教程) templateclass SP { 私人: T*pData;//指针 RC*reference;//引用计数 公众: SP():pData(0),reference
templateclass SP
{
私人:
T*pData;//指针
RC*reference;//引用计数
公众:
SP():pData(0),reference(0)
{
//创建新引用
reference=newrc();
//增加引用计数
reference->AddRef();
}
SP(T*pValue):pData(pValue),参考(0)
{
//创建新引用
reference=newrc();
//增加引用计数
reference->AddRef();
}
SP(常量SP和SP):pData(SP.pData)、参考(SP.reference)
{
//复制构造函数
//复制数据和引用指针
//并增加引用计数
reference->AddRef();
}
~SP()
{
//析构函数
//减少引用计数
//如果引用变为零,则删除数据
如果(参考->发布()==0)
{
删除pData;
删除引用;
}
}
T&运算符*()
{
返回*pData;
}
T*运算符->()
{
返回pData;
}
SP和运算符=(常量SP和SP)
{
//赋值运算符
if(this!=&sp)//避免自分配
{
//减少旧的引用计数
//如果引用变为零,则删除旧数据
如果(参考->发布()==0)
{
删除pData;
删除引用;
}
//复制数据和引用指针
//并增加引用计数
pData=sp.pData;
参考=sp.reference;
reference->AddRef();
}
归还*这个;
}
};
编辑:
要实现这一点,我必须有一个指向原始类型的指针
我在这里发布了一个问题:
但现在,自从看到评论和答案后,我认为两者都是相关的。我有一个构造器:
template <typename T>
template <typename U>
Sptr<T>::Sptr(U* u) : obj(u),ref(NULL) {
//do something
ref = new RC();
ref->AddRef();
}
模板
模板
Sptr::Sptr(U*U):对象(U),参考(NULL){
//做点什么
ref=新的RC();
ref->AddRef();
}
现在考虑<代码> Sptr sp(新派生);<代码>其中
派生
派生自Base1
。Base1具有受保护的构造函数/析构函数。
它是为类型为
T
的对象存储的,但我需要通过类型为U的对象存储它。我需要保留它。我该怎么做?您的智能指针需要3块信息
首先,指向数据的指针(T*
或其他东西)
其次,您的引用计数:std::atomic
或其他什么
第三,你的销毁函数(std::function
或其他东西)
首次创建智能指针时,将创建销毁函数。当您的智能指针复制到另一个智能指针时,将复制此销毁函数。如果新智能指针的类型与旧的不匹配,则销毁函数将以与类型兼容的方式包装(std::function=std::function是否可以开箱即用?无论如何,基本上就是这样做的)
默认情况下,此销毁功能仅为delete t
,但作为一个附带好处,这允许智能指针的用户传入销毁功能,该功能并不总是delete t
有趣的是,在相当于重置的情况下,您替换了销毁功能。因此,您实际上可以将销毁函数的签名设置为std::function
,这使得在T
和U
类型智能指针之间移动它变得更加容易
template < typename T > class SP
{
private:
T* pData; // pointer
RC* reference; // Reference count
std::function<void()> destroyData;
public:
template<typename U>
SP(U* pValue):
pData(pValue),
reference(nullptr),
// store how to destroy pValue now, for later execution:
destroyData([pValue]()->void{
delete pValue;
})
{
// Create a new reference
reference = new RC();
// Increment the reference count
reference->AddRef();
}
// similar for operator=, and you may have to do something for SP<T> as well:
template<typename U>
SP(const SP<U>& sp):
pData(sp.pData),
reference(sp.reference),
destroyData(sp.destroyData)
{
// Copy constructor
// Copy the data and reference pointer
// and increment the reference count
reference->AddRef();
}
template<typename U>
SP<T>& operator = (const SP<U>& sp)
{
// blah blah blah, then
destroyData = sp.destroyData;
}
~SP()
{
// Destructor
// Decrement the reference count
// if reference become zero delete the data
if(reference->Release() == 0)
{
delete reference;
destroyData(); // here I destroyed it!
}
}
};
templateclass SP
{
私人:
T*pData;//指针
RC*reference;//引用计数
std::函数数据;
公众:
模板
SP(U*P值):
pData(pValue),
参考(空PTR),
//存储如何立即销毁pValue,以便以后执行:
销毁数据([pValue]()->void{
删除pValue;
})
{
//创建新引用
reference=newrc();
//增加引用计数
reference->AddRef();
}
//operator=的情况类似,您可能还需要为SP执行一些操作:
模板
SP(常数SP和SP):
pData(sp.pData),
参考(sp.reference),
destroyData(sp.destroyData)
{
//复制构造函数
//复制数据和引用指针
//并增加引用计数
reference->AddRef();
}
模板
SP和运算符=(常量SP和SP)
{
//废话废话,那么
destroyData=sp.destroyData;
}
~SP()
{
//析构函数
//减少引用计数
//如果引用变为零,则删除数据
如果(参考->发布()==0)
{
删除引用;
destroyData();//我把它毁了!
}
}
};
或者类似的另一种方法是将删除任务委托给另一个类
// non templated base
class DeleterBase {
public:
virtual ~DeleterBase() { };
};
template <typename T>
class Deleter : public DeleterBase {
private:
T *ptr;
public:
Deleter(T *p) // remember the pointer with the correct type here
: ptr{p}
{ }
~Deleter() {
delete this->ptr; // invokes correct destructor
}
};
//非模板基
类DeleterBase{
公众:
虚拟~DeleterBase(){};
};
模板
类Deleter:公共DeleterBase{
私人:
T*ptr;
公众:
Deleter(T*p)//记住此处具有正确类型的指针
:ptr{p}
{ }
~Deleter(){
删除此->ptr;//调用正确的析构函数
}
};
现在在智能指针中:
template <typename T>
class SP {
private:
T *p;
DeleterBase *deleter;
public:
template <typename U> // U is deduced to actual type
explicit SP(U *p)
: p{p},
deleter{new Deleter<U>(p)} // correct type
{ }
// transfer control in the move constructor/assignment
// increase the ref count in copy constructor/assignment
// now just delete the deleter in the dtor
~SP() {
if (reference_count_is_zero()) { // however you implement this
delete this->deleter;
}
}
};
t
template <typename T>
class SP {
private:
T *p;
DeleterBase *deleter;
public:
template <typename U> // U is deduced to actual type
explicit SP(U *p)
: p{p},
deleter{new Deleter<U>(p)} // correct type
{ }
// transfer control in the move constructor/assignment
// increase the ref count in copy constructor/assignment
// now just delete the deleter in the dtor
~SP() {
if (reference_count_is_zero()) { // however you implement this
delete this->deleter;
}
}
};