Как избежать строгих ошибок алиасинга при использовании align_storage

я использую std::aligned_storage в качестве резервного хранилища для варианта шаблона. Проблема в том, как только я включу -O2 на gcc я начинаю получать предупреждения о том, что «разыменование указателя типа-наказанного нарушит строгий псевдоним».

Реальный шаблон намного сложнее (тип проверяется во время выполнения), но минимальный пример для генерации предупреждения:

struct foo
{
std::aligned_storage<1024> data;

// ... set() uses placement new, stores type information etc ...

template <class T>
T& get()
{
return reinterpret_cast<T&>(data); // warning: breaks strict aliasing rules
}
};

я точно уверен boost::variant по сути дела делает то же самое, что и это, но я не могу понять, как они избегают этой проблемы.

Мои вопросы:

  • При использовании aligned_storage таким образом нарушает строгие псевдонимы, как я должен его использовать?
  • Есть ли на самом деле проблема сглаживания в get() учитывая, что в функции нет других операций с указателями?
    • А если get() встраивается?
    • Как насчет get() = 4; get() = 3.2? Может ли эта последовательность быть переупорядочена из-за int а также float быть разными типами?

5

Решение

std::aligned_storage это часть <type_traits>; как и большинство остальных обитателей этого заголовочного файла, он просто является держателем для некоторых typedef и не предназначен для использования в качестве типа данных. Его работа заключается в определении размера и выравнивания и создании типа POD с этими характеристиками.

Вы не можете использовать std::aligned_storage<Len, Align> непосредственно. Вы должны использовать std::aligned_storage<Len, Align>::typeпреобразованный тип, который представляет собой «тип POD», подходящий для использования в качестве неинициализированного хранилища для любого объекта, размер которого не превышает Len и чье выравнивание является делителем Align. «(Align по умолчанию наибольшее полезное выравнивание больше или равно Len.)

Как отмечает стандарт C ++, обычно тип, возвращаемый std::aligned_storage будет массив (указанного размера) unsigned char с указателем выравнивания. Это позволяет избежать правила «отсутствия строгого псевдонима», поскольку тип символа может иметь псевдоним любого другого типа.

Так что вы можете сделать что-то вроде:

template<typename T>
using raw_memory = typename std::aligned_storage<sizeof(T),
std::alignment_of<T>::value>::type;

template<typename T>
void* allocate() { return static_cast<void*>(new raw_memory<T>); }

template<typename T, typename ...Arg>
T* maker(Arg&&...arg) {
return new(allocate<T>()) T(std::forward<Arg>(arg)...);
}
5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]