父类使用默认构造函数;儿童班'意外地调用了析构函数

时间:2017-03-28 20:09:17

标签: c++ c++11

我有一个C ++场景,在我没有预料到的情况下调用孩子的析构函数。最小的复制品如下:

#include <cstdio>
#include <memory>

using namespace std;

class Parent {
public:
};

class Child : public Parent {
    public:
    ~Child() {
        printf("Got here\n");
    }
};

int 
main()
{
    shared_ptr<Parent> x(new Child);
}

通常这样的事情就是一个错误。开发人员打算调用子析构函数,正确的操作是将空虚拟析构函数插入父级。然而,令我震惊的是,G ++ 4.4.7(是的,我知道它已经老了)和clang 3.4.2编译它,这样就可以调用子析构函数

这是否符合标准?

2 个答案:

答案 0 :(得分:5)

即使shared_ptr没有特殊魔法,delete父指针与非虚拟析构函数只是未定义的行为,所以结果(调用子析构函数)肯定会顺从。

但在这种情况下shared_ptr&#34;记得&#34;传递给它的原始对象的类型,并通过子指针(通过其存储的删除器)销毁它。

答案 1 :(得分:0)

一个独特的ptr会搞砸到这里。但共享ptr会做一些&#34;魔术&#34;这里。

shared_ptr<T> has two things they manage; the T *`和引用计数块。

引用计数块包含两个atomic<std::size_t>,一个用于强引用,一个用于弱引用,以及一个类型擦除的删除器。此std::function - 类似已删除的删除器会记住如何删除您拥有的内容。

使用shared_ptr构建任何U*u时,默认情况下会将[u]{std::default_delete<U>{}(u);}存储在该删除工具中。

实际上,它会记住如何根据传入的类型删除对象。

shared_ptr非常灵活。

您可以传入自定义删除器来替换默认删除器,您可以使用别名构造函数来分割使用的T*存储的引用计数块,您可以使用make_shared来分配引用在同一内存分配中计数块和T

引用计数块的开销是它存储删除器的原因;考虑到我们无论如何都需要块,它并不被认为过于昂贵。相比之下,unique_ptr默认情况下没有这样的事情;您必须明确添加删除器,并且如果您需要,您必须默认管理shared_ptr为您执行的所有花哨技巧。对于原始拥有指针,unique_ptr基本上没有开销; shared_ptr具有明显的开销,但与内存分配开销相比通常很小。