如何通过' Placement New'来构建无析构函数类型。

时间:2017-02-17 22:15:02

标签: c++ c++11 stl

所以我构建了一个类,我打算使用std::aligned_storage来存储最多16个字节的不同类型,以用于变体'类。从理论上讲,它应该能够存储任何POD类型和常见容器,例如std::stringstd::map

我按照此处找到的代码示例进行操作,看起来它的确是为了我正在寻找的内容:http://en.cppreference.com/w/cpp/types/aligned_storage

我的版本,基本上是:

class Variant {
public:
    Variant() { /* construct */ }
    Variant(std::map<int,int> v) {
        new(&m_data) std::map<int,int>(v);  // construct std::map<int,int> at &m_data
        m_type = TYPE_MAP;
    }
    ~Variant() {
        if (m_type == TYPE_MAP) {
            // cool, now destruct..?
            reinterpret_cast<std::map<int, int>*>(&m_data)->~/*???????????????*/();
        }
    }

private:
    // type of object in m_data
    enum Type m_type;
    // chunk of space for allocating to
    std::aligned_storage<16, std::alignment_of<std::max_align_t>::value>::type m_data;
};

我的问题伴随着破坏。正如您在/*???????????????*/所看到的,我不确定在cppreference.com示例中代替~T()应该拨打什么电话:

reinterpret_cast<const T*>(data+pos)->~T();  // I did the same thing except I know what T is, is that a problem is it?

在我看来,我做了完全相同的事情,无视模板匿名。问题是,std::map没有任何std::map::~map()析构函数方法,只有std::map::~_Tree,这显然不是为了直接使用。那么,在cppreference.com示例代码中,如果~T()T,那么std::map<int,int>会调用什么,以及我为一个对象调用析构函数的正确方法是什么std::aligned_storage中的已知类型?或者我是否使事情复杂化并且这些STL容器中的clear()方法是否相当于完全销毁?

或者,有没有更简单的方法呢?因为我可能误解了我对std::aligned_storage的预期用法的看法。

2 个答案:

答案 0 :(得分:5)

听起来你已经读过定义了std::map的头文件,并认为std::map没有析构函数,因为你找不到析构函数的声明。

但是,在C ++中,没有声明析构函数的类型将具有编译器声明的析构函数隐式。这个隐式析构函数将调用基数和非静态成员的析构函数。听起来您的库实现中的std::map_Tree上的薄层。因此,破坏地图需要做的就是破坏树。因此,编译器的默认析构函数可以解决问题。

允许在你的情况下编写->~map(),它将调用隐式定义的析构函数,并且地图将被正确销毁。您也可以将此语法用于标量类型,例如int(但由于某种原因,不是数组)。

答案 1 :(得分:2)

  

我不知道该怎么称呼~T()

您的类型,名为map

reinterpret_cast<std::map<int, int>*>(&m_data)->~map();

如果它让你感觉更好,你可以放入一个功能模板:

template <class T>
void destroy_as(void* p) {
    static_cast<T*>(p)->~T();
}

destroy_as<std::map<int, int>>(&m_data);
  

问题是,std::map没有任何std::map::~map()析构函数方法

它可能是编译器生成的,但类型确定具有析构函数。所有类型都有析构函数。有些可能是明确的或实现的delete d,但它们存在。

请注意,aligned_storage太小,无法存储mapsizeof(std::map)大于16。