问题描述
我正在使用 std :: aligned_storage
作为变体模板的后备存储.问题是,一旦我在gcc上启用 -O2
,我就会开始收到取消引用类型化指针的警告会破坏严格的别名"的警告.
I'm using std::aligned_storage
as the backing storage for a variant template. The problem is, once I enable -O2
on gcc I start getting warnings of 'dereferencing type-punned pointer will break strict aliasing`.
真正的模板要复杂得多(在运行时检查类型),但是生成警告的最小示例是:
The real template is much more complex (type checked at runtime), but a minimal example to generate the warning is:
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
与此基本相同,但是我似乎找不到他们如何避免此问题的方法.
I'm pretty sure boost::variant
is doing essentially the same thing as this, but I can't seem to find how they avoid this issue.
我的问题是:
- 如果以这种方式使用
aligned_storage
违反了严格混叠,我应该如何使用它? - 考虑到函数中没有其他基于指针的操作,
get()
中是否确实存在严格的混叠问题?- 如果内联
get()
怎么办? -
get()= 4怎么样?get()= 3.2
?由于int
和float
是不同的类型,该序列是否可以重新排序?
- If using
aligned_storage
in this way violates strict-aliasing, how should I be using it? - Is there actually a strict-aliasing problem in
get()
given that there are no other pointer based operations in the function?- What about if
get()
is inlined? - What about
get() = 4; get() = 3.2
? Could that sequence be reordered due toint
andfloat
being different types?
推荐答案
std :: aligned_storage
是< type_traits>
的一部分;像该头文件的其余大多数居民一样,它只是某些typedef的持有人,并不意味着被用作数据类型.它的工作是获取大小和对齐方式,并为您提供具有这些特征的POD类型.std::aligned_storage
is part of<type_traits>
; like most of the rest of the inhabitants of that header file, it is just a holder for some typedefs and is not meant to be used as a datatype. Its job is to take a size and alignment, and make you a POD type with those characteristics.您不能直接使用
std :: aligned_storage< Len,Align>
.您必须使用std :: aligned_storage< Len,Align> :: type
,即转换后的类型,该类型是"POD类型,适用于任何大小最大为 Len ,并且其对齐方式是Align
的除数."(Align
默认为大于或等于Len
的最大有用对齐方式.)You cannot use
std::aligned_storage<Len, Align>
directly. You must usestd::aligned_storage<Len, Align>::type
, the transformed type, which is "a POD type suitable for for use as uninitialized storage for any object whose size is at mostLen
and whose alignment is a divisor ofAlign
." (Align
defaults to the largest useful alignment greater than or equal toLen
.)正如C ++标准所指出的那样,
std :: aligned_storage
返回的类型通常是带有对齐说明符的unsigned char
的数组(具有指定大小).这样可以避免使用没有严格的别名"规则,因为字符类型可以别名任何其他类型.As the C++ standard notes, normally the type returned by
std::aligned_storage
will be an array (of the specified size) ofunsigned char
with an alignment specifier. That avoids the "no strict aliasing" rule because a character type may alias any other type.所以您可能会做类似的事情:
So you might do something like:
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)...); }
这篇关于使用aligned_storage时如何避免严格的别名错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
- What about if
- 如果内联