2017-02-17 2 views
2

Итак, у меня есть класс, с которым я намеревался использовать std::aligned_storage для хранения различных типов до 16 байтов для класса «Вариант». Теоретически он должен иметь возможность хранить любой тип POD и обычные контейнеры, такие как std::string и std::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; 
}; 

Моя проблема возникает с разрушение. Как вы можете видеть на /*???????????????*/, я не уверен, что называть вместо ~T() в примере cppreference.com:

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? Или я слишком усложняю вещи, и методы clear() в этих контейнерах STL гарантируют выполнение эквивалента полного уничтожения?

Или, есть ли более простой способ обойти это? Как я, возможно, неправильно понял что-то по поводу моего предполагаемого использования std::aligned_storage.

+4

Что заставляет вас думать, что нет 'std :: map :: ~ map()'? Конечно. – Brian

+0

А, я собирался спросить, было ли это вообще связано с моим компилятором, но, должно быть, отредактировал его. Итак, я рассматриваю проблему с поддержкой Visual Studio 2015 C++ 11 или что-то здесь? Поскольку в файле заголовка почти нет ни одного ... @Brian – Deji

+2

Все классы имеют деструктор (компилятор неявно объявляет, если вы этого не делаете), и вы также можете использовать синтаксис '~ T()' для типов неклассов, для которых он определен как нет-op –

ответ

5

Это звучит, как вы прочитать файл заголовка, в котором std::map определяется и думать, что std::map не имеет деструктор, потому что вы не смогли найти объявление деструктора.

Однако в C++ тип, который не имеет объявленного деструктора, будет иметь деструктор неявно, объявленный компилятором. Этот неявный деструктор вызовет деструкторы баз и нестатических членов. Похоже, что std::map в вашей реализации библиотеки - это тонкий слой поверх _Tree. Поэтому все, что нужно сделать, чтобы уничтожить карту, - это уничтожить дерево. Поэтому деструктор по умолчанию для компилятора делает трюк.

В вашем случае разрешено записывать ->~map(), и он вызовет неявно определенный деструктор, и карта будет уничтожена правильно. Вы также можете использовать этот синтаксис со скалярными типами, такими как int (но не массивы, по какой-то причине).

+0

А, так что я просто преждевременно отстранен от недостатка присутствия в предложениях Visual Studio Intellisense и самого файла заголовка. Наверное, я просто думал, что есть что-то особенное неправильно с _explicit_ уничтожением определенных объектов. D'о! – Deji

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 слишком мал, чтобы хранить map, sizeof(std::map) больше чем 16.

+0

Кажется, что 12 в реализации Visual Studios, я не так удивлен, что это не то же самое по всем направлениям. Я адаптировал свой пример из моего источника, который использовал 'std :: string' (поскольку он имел' std :: string :: ~ basic_string() ', что делало ситуацию менее очевидной загадкой). Я планировал добавить поддержку «std: map», хотя, так что это напоминает мне, что мне нужно проверить это глубже, прежде чем продолжить, спасибо. – Deji

Смежные вопросы