Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 避免对非虚拟析构函数进行对象切片_C++_Templates_Pointers_G++_Smart Pointers - Fatal编程技术网

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;
            }
        }
};