避免对非虚拟析构函数进行对象切片 [英] Avoid object slicing for non-virtual destructors
问题描述
我正在为智能指针编写代码作为练习。在线使用教程( 1 , 2 )我开发了一个具有引用计数的普通智能指针类。问题是我找不到以下内容:
当智能指针检测到没有更多引用存在
时特定对象时,即使最终智能
指针的模板参数是基本类型,它也必须通过指向
原始类型的指针来删除该对象。这是为了避免对
非虚拟析构函数进行对象分片。
我该如何实现这一点。基本上我的代码如下所示(来自教程)。
template< typename T> SP
{
private:
T * pData; //指针
RC *引用; //引用计数
public:
SP():pData(0),reference(0)
{
//创建一个新引用
reference = new RC();
//增加引用计数
reference-> AddRef();
SP(T * pValue):pData(pValue),reference(0)
{
//创建一个新的引用
reference =新的RC();
//增加引用计数
reference-> AddRef();
SP(const SP< T& sp):pData(sp.pData),reference(sp.reference)
{
// Copy构造函数
//复制数据和引用指针
//并增加引用计数
reference-> AddRef();
$ b〜SP()
{
//析构函数
//减少引用计数
//如果引用变为零删除数据
if(reference-> Release()== 0)
{
delete pData;
删除参考;
}
}
T&运算符*()
{
return * pData;
}
T * operator-> ()
{
return pData;
}
SP< T>& operator =(const SP< T& sp)
{
//赋值运算符
if(this!=& sp)//避免自赋值
{
//减少旧的引用计数
//如果引用变为零删除旧的数据
if(reference-> Release()== 0)
{
delete的pData;
删除参考;
}
//复制数据和引用指针
//并增加引用计数
pData = sp.pData;
reference = sp.reference;
reference-> AddRef();
}
return * this;
}
};
编辑:
为了实现这一点,我必须有一个指向原始类型的指针。
我在这里发布了一个问题: 但是现在查看评论和回答后,我认为两者都是相关的。我有构造函数: 现在考虑 您的智能指针需要3块信息。 首先,指向数据的指针( 当第一次创建智能指针时,销毁功能被创建。当你的智能指针被复制到另一个智能指针时,这个销毁功能被复制。如果新智能指针的类型与旧版本不匹配,那么该销毁函数会以类型兼容的方式进行封装(不是 这个销毁函数只是 有趣的是,相当于 或类似的东西 I am writing code for smart pointers as an exercise. Using tutorials online (1 , 2) I have developed a normal smart-pointer class with reference counting. The problem is I am unable to figure out the following: when the smart pointer detects that no more references exist to a
particular object, it must delete the object via a pointer to the
original type, even if the template argument of the final smart
pointer is of a base type. This is to avoid object slicing for
non-virtual destructors. How can I achieve that. Basically my code looks like below (from the tutorial). EDIT: To achieve that I have to have a pointer to the original type. I have posted a question here: delete via a pointer to Derived, not Base But Now since viewing the comments and answers I think both are related. I have the constructor: Now consider Your smart pointer needs 3 chunks of information. First, the pointer to the data ( Second, your reference count: Third, your destruction function ( When the smart pointer is first created, that destruction function is created. When your smart pointer is copied to another smart pointer, this destruction function is copied. If the type of the new smart pointer doesn't match the old, that destruction function gets wrapped up in a type-compatible way (does By default, this destruction function is just Amusingly, on the equivalent of or something like that 这篇关于避免对非虚拟析构函数进行对象切片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
template< typename T>
模板< typename U>
Sptr< T> :: Sptr(U * u):obj(u),ref(NULL){
//做某事
ref = new RC();
ref-> AddRef();
}
Sptr< Base1> sp(new Derived);
其中派生
来自 Base1
。 Base1保护了构造函数/析构函数。
这是为 T
类型的对象存储的,但我需要通过类型为U的对象存储它。我需要保留它。我怎么做到这一点?
T *
或其他)。引用计数: std :: atomic< int>
或者其他。 std :: function< void(T *)>
或者其他东西)。
std :: function< void(Base *)> = std: :function< void(Derived *)>
开箱即用?无论如何,你基本上都是这样做的)。
delete t
,但是作为一个好处,它允许智能指针的用户传入一个销毁函数,它并不总是删除t
。
reset
,您替换你的销毁功能。所以你实际上可以使破坏函数的签名是 std :: function< void()>
,这使得它在 T <
>模板< typename T> SP
{
private:
T * pData; //指针
RC *引用; //引用计数
std :: function< void()> destroyData;
public:
模板< typename U>
SP(U * pValue):
pData(pValue),
reference(nullptr),
//存储如何现在销毁pValue,以便稍后执行:
destroyData([pValue]() - > void {
delete pValue;
})
{
//创建一个新的引用
reference = new RC() ;
//增加引用计数
reference-> AddRef();
}
//对于operator =类似,并且您可能必须为SP< T>做些事情。以及:
模板< typename U>
SP(常数SP<& sp):
pData(sp.pData),
reference(sp.reference),
destroyData(sp.destroyData)
{
//复制构造函数
//复制数据和引用指针
//并增加引用计数
reference-> AddRef();
}
模板< typename U>
SP< T>& operator =(const SP& sp)
{
//等等等等,然后
destroyData = sp.destroyData;
$ b〜SP()
{
//析构函数
//减少引用计数
//如果引用变为零删除数据
if(reference-> Release()== 0)
{
delete reference;
destroyData(); //在这里我毁了它!
}
}
};
template < typename T > class SP
{
private:
T* pData; // pointer
RC* reference; // Reference count
public:
SP() : pData(0), reference(0)
{
// Create a new reference
reference = new RC();
// Increment the reference count
reference->AddRef();
}
SP(T* pValue) : pData(pValue), reference(0)
{
// Create a new reference
reference = new RC();
// Increment the reference count
reference->AddRef();
}
SP(const SP<T>& sp) : pData(sp.pData), reference(sp.reference)
{
// Copy constructor
// Copy the data and reference pointer
// and increment the reference count
reference->AddRef();
}
~SP()
{
// Destructor
// Decrement the reference count
// if reference become zero delete the data
if(reference->Release() == 0)
{
delete pData;
delete reference;
}
}
T& operator* ()
{
return *pData;
}
T* operator-> ()
{
return pData;
}
SP<T>& operator = (const SP<T>& sp)
{
// Assignment operator
if (this != &sp) // Avoid self assignment
{
// Decrement the old reference count
// if reference become zero delete the old data
if(reference->Release() == 0)
{
delete pData;
delete reference;
}
// Copy the data and reference pointer
// and increment the reference count
pData = sp.pData;
reference = sp.reference;
reference->AddRef();
}
return *this;
}
};
template <typename T>
template <typename U>
Sptr<T>::Sptr(U* u) : obj(u),ref(NULL) {
//do something
ref = new RC();
ref->AddRef();
}
Sptr<Base1> sp(new Derived);
where Derived
is derived from Base1
. Base1 has protected constructor/destructor.
Which is storing for an object of type T
But I need to store it through an object of type U. I need to preserve that. How can I do that?T*
or something).std::atomic<int>
or something.std::function<void(T*)>
or something).std::function<void(Base*)> = std::function<void(Derived*)>
work out of the box? Regardless, you are basically doing that).delete t
, but as a side benefit, this allows the users of your smart pointer to pass in a destruction function, which isn't always delete t
.reset
, you replace your destruction function. So you could actually make the signature of the destruction function be std::function<void()>
, which makes moving it between T
and U
type smart pointers a tad easier.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!
}
}
};