Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.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++ 共享\u ptr魔法:)_C++_Destructor_Smart Pointers - Fatal编程技术网

C++ 共享\u ptr魔法:)

C++ 共享\u ptr魔法:),c++,destructor,smart-pointers,C++,Destructor,Smart Pointers,:) Lidström先生的主张是,一个结构共享ptr p(新派生)不要求Base具有虚拟析构函数: Armen Tsirunyan:“真的吗?共享的ptr会正确清理吗?在这种情况下,你能演示一下如何实现这种效果吗?” < Daniel Lidstr >μ>强:“SyddypTR使用它自己的析构函数删除具体实例。这在C++社区中被称为RAII。我的建议是,您可以了解RAII的所有内容。当您在所有情况下使用RAII时,它将使您的C++编码变得更容易。” 阿门·齐鲁尼亚:“我知道RAII,我也知道

:)

Lidström先生的主张是,一个结构
共享ptr p(新派生)不要求Base具有虚拟析构函数:

Armen Tsirunyan:“真的吗?共享的ptr会正确清理吗?在这种情况下,你能演示一下如何实现这种效果吗?”

< Daniel Lidstr >μ>强:“SyddypTR使用它自己的析构函数删除具体实例。这在C++社区中被称为RAII。我的建议是,您可以了解RAII的所有内容。当您在所有情况下使用RAII时,它将使您的C++编码变得更容易。” 阿门·齐鲁尼亚:“我知道RAII,我也知道最终共享的解构器可能会在pn达到0时删除存储的px。但是如果px有指向

Base
的静态类型指针和指向
派生的
的动态类型指针,那么除非
Base
有一个虚拟析构函数,否则这将导致未定义的行为。如果我错了,请纠正我。”

Daniel Lidström:“共享ptr知道静态类型是具体的。它知道这一点,因为我在它的构造函数中传递了它!看起来有点像魔术,但我可以向你保证它是精心设计的,非常漂亮。”

那么,判断一下我们,在不要求多态类具有虚拟析构函数的情况下,如何实现共享的_ptr呢? 提前感谢

简单地说

shared_ptr
使用特殊的deleter函数,该函数由始终使用 给定对象的析构函数,而不是Base的析构函数,这是模板元编程的一点工作,但它可以工作

诸如此类

template<typename SomeType>
shared_ptr(SomeType *p)
{
   this->destroyer = destroyer_function<SomeType>(p);
   ...
}
模板
共享ptr(SomeType*p)
{
该->销毁程序=销毁程序功能(p);
...
}
简单地说

shared_ptr
使用特殊的deleter函数,该函数由始终使用 给定对象的析构函数,而不是Base的析构函数,这是模板元编程的一点工作,但它可以工作

诸如此类

template<typename SomeType>
shared_ptr(SomeType *p)
{
   this->destroyer = destroyer_function<SomeType>(p);
   ...
}
模板
共享ptr(SomeType*p)
{
该->销毁程序=销毁程序功能(p);
...
}

创建共享\u ptr时,它会在自身内部存储一个删除器对象。当共享\u ptr即将释放指向的资源时,会调用此对象。因为您知道如何在构建时销毁资源,所以可以使用类型不完整的共享\u ptr。创建共享\u ptr的人会在其中存储正确的删除器

例如,您可以创建自定义删除器:

void DeleteDerived(Derived* d) { delete d; } // EDIT: no conversion needed.

shared_ptr<Base> p(new Derived, DeleteDerived);
void delete派生(派生*d){delete d;}//编辑:无需转换。
共享_ptr p(新派生、删除派生);

p将调用DeleteDerived来销毁指向的对象。实现会自动执行此操作。

创建共享\u ptr时,它会在自身内部存储一个deleter对象。当共享\u ptr即将释放指向的资源时,会调用此对象。因为您知道如何在构建点销毁资源,所以可以使用共享类型不完整的d_ptr。创建共享_ptr的人在其中存储了正确的删除器

例如,您可以创建自定义删除器:

void DeleteDerived(Derived* d) { delete d; } // EDIT: no conversion needed.

shared_ptr<Base> p(new Derived, DeleteDerived);
void delete派生(派生*d){delete d;}//编辑:无需转换。
共享_ptr p(新派生、删除派生);

p将调用DeleteDerived来销毁指向的对象。实现会自动执行此操作。

是的,可以通过这种方式实现shared_ptr。Boost会这样做,C++11标准也要求这种行为。作为一种附加的灵活性,shared_ptr管理的不仅仅是一个引用计数器。所谓的deleter通常被放入同一个内存块也包含引用计数器。但有趣的是,此删除器的类型不是共享\u ptr类型的一部分。这称为“类型擦除”,基本上与用于实现“多态函数”的技术相同“boost::function或std::function用于隐藏实际函子的类型。为了使您的示例正常工作,我们需要一个模板化构造函数:

template<class T>
class shared_ptr
{
public:
   ...
   template<class Y>
   explicit shared_ptr(Y* p);
   ...
};
模板
类共享\u ptr
{
公众:
...
模板
显式共享ptr(Y*p);
...
};
所以,如果你把它用于你的基类和派生类

class Base {};
class Derived : public Base {};

int main() {
   shared_ptr<Base> sp (new Derived);
}
类基{};
派生类:公共基{};
int main(){
共享ptr sp(新衍生);
}
。。。Y=Derived的模板化构造函数用于构造共享的\u ptr对象。因此,构造函数有机会创建适当的删除器对象和引用计数器,并将指向此控制块的指针存储为数据成员。如果引用计数器达到零,则将使用先前创建和派生的aware deleter来处理该对象

C++11标准对该构造函数(20.7.2.2.1)有如下说明:

要求:
p
必须可转换为
T*
<代码>Y
应为完整类型表达式
delete p
应格式良好,具有明确的行为,且不得引发异常。

效果:构造一个
共享的\u ptr
对象,该对象拥有指针
p

对于析构函数(20.7.2.2.2):

效果:如果
*此
为空或与另一个
共享的\u ptr
实例共享所有权(
使用\u count()>1
),则没有副作用。 否则,如果
*此
拥有对象
p
和删除器
d
,则调用
d(p)
否则,如果
*此
拥有指针
p
,则调用
delete p


(我用粗体强调)。

是的,用这种方式实现共享ptr是可能的。Boost确实如此,C++11标准也要求这种行为。作为一种额外的灵活性,shared_ptr不仅仅管理一个参考计数器。通常将所谓的删除器放入