C++ 在C++;11
关于C++11/14标准,在幻灯片15中,作者写道“许多经典的编码规则在C++11中不再适用”。他列举了三个例子,我同意三个法则和内存管理 然而,他的第二个例子是“具有虚拟成员的虚拟析构函数”(仅此而已)这意味着什么?我知道,如果我们有类似于C++ 在C++;11,c++,c++11,virtual-destructor,C++,C++11,Virtual Destructor,关于C++11/14标准,在幻灯片15中,作者写道“许多经典的编码规则在C++11中不再适用”。他列举了三个例子,我同意三个法则和内存管理 然而,他的第二个例子是“具有虚拟成员的虚拟析构函数”(仅此而已)这意味着什么?我知道,如果我们有类似于 Base *b = new Derived; ... delete b; 这里有很好的解释: 但是现在在C++11中,如果您有虚拟成员,那么声明虚拟析构函数没有用吗?链接的文章显示了相关代码: std::unique_ptr<Derived>
Base *b = new Derived;
...
delete b;
这里有很好的解释:
但是现在在C++11中,如果您有虚拟成员,那么声明虚拟析构函数没有用吗?链接的文章显示了相关代码:
std::unique_ptr<Derived> { new Derived };
std::unique_ptr{new Derived};
存储的删除程序是std::default_delete
,它不要求Base::~Base
是虚拟的
现在您可以将其移动到unique\u ptr
,它还将移动std::default\u delete
,而无需将其转换为std::default\u delete
。
我认为这与演示中其他地方提到的“零规则”有关
如果您只有自动成员变量(即,对于可能是原始指针的成员,使用
shared_ptr
或unique_ptr
),那么您不需要编写自己的复制或移动构造函数或赋值运算符——编译器提供的默认值将是最佳的。使用类内初始化,您也不需要默认构造函数。最后,您根本不需要编写析构函数,不管是虚拟的还是非虚拟的。作为幻灯片的作者,我将尝试澄清
如果编写代码时使用new
显式分配派生的
实例,并使用基类指针使用delete
销毁它,则需要定义一个虚拟的
析构函数,否则最终将不完全销毁派生的
实例。但是,我建议完全避免使用new
和delete
,并专门使用shared\u ptr
来引用堆分配的多态对象,如
shared_ptr<Base> pb=make_shared<Derived>();
shared_ptr pb=make_shared();
这样,即使使用shared\u ptr
表示,共享指针也会跟踪要使用的原始析构函数。一旦最后一个引用的shared\u ptr
超出范围或被重置,将调用~Derived()
,并释放内存。因此,您不需要将~Base()
设置为虚拟
unique_ptr
和make_unique
不提供此功能,因为它们不提供有关删除器的shared_ptr
机制,因为unique指针简单得多,以最低的开销为目标,因此不存储删除器所需的额外函数指针。使用unique\u ptr
时,deleter函数是类型的一部分,因此,带有deleter的uniqe\u ptr引用~派生的将与使用默认deleter的unique\u ptr
不兼容,如果~Base
不是虚拟的,这对于派生实例来说无论如何都是错误的
我提出的个人建议,是为了易于遵循,并一起遵循。他们试图通过让所有资源管理由库组件和编译器生成的代码来完成,从而生成更简单的代码
定义类中的(虚)析构函数,将禁止编译器提供的移动构造函数/赋值操作符,并且可能禁止编译器提供的复制构造函数/赋值操作符在C++的未来版本中。使用
=default
恢复它们变得很容易,但看起来仍然像很多样板代码。最好的代码是您不必编写的代码,因为它不会出错(我知道该规则仍有例外)
将“不要定义(虚拟)析构函数”总结为我的“零规则”的推论:
每当您在现代C++中设计多态(OO)类层次结构,并希望/或需要在堆上分配实例并通过基类指针访问它们时,使用<代码> MaMaJuffSyd()/Script >实例化它们,并<代码> SyddyPtR <代码>以保持它们。这允许您保持“零规则”
这并不意味着您必须分配堆上的所有多态对象。例如,定义一个以(Base&)
为参数的函数,可以使用一个本地派生的
变量调用,而不会出现问题,并且相对于Base
的虚拟成员函数,它的行为将是多态的
在我看来,动态OO多态性在许多系统中被过度使用。当我们使用C++时,我们不应该像java那样编程,除非我们遇到问题,其中堆分配对象的动态多态性是正确的解决方案。p> 要回答具体问题
但是现在在C++11中,如果您有虚拟成员,那么声明虚拟析构函数是没有用的吗
在C++11核心语言中,对虚拟析构函数的需求没有改变。如果要使用基指针删除派生对象,则必须将析构函数声明为虚拟
幻灯片中的语句给人的印象是,C++11以某种方式改变了虚拟析构函数的行为——事实并非如此。正如作者所阐明的,它仅在使用共享\u ptr
时适用。但在冗长的解释中,虚拟析构函数仍然是必需的(除了使用shared\u ptr
)这一事实被淡化了 这只是一个猜测,但在使用智能指针时,可以安排调用正确的析构函数,即使基析构函数不是虚拟的。这是在shared_ptr
中开箱即用的情况下发生的。大意是三的规则或不再需要虚拟析构函数的声明非常简单