Fre*_*pin 5 c++ gcc strict-aliasing gcc7
我写的代码在GCC 4.9,GCC 5和GCC 6中是无警告的.它也是一些较旧的GCC 7实验快照的警告(例如7-20170409).但是在最近的快照(包括第一个RC)中,它开始产生关于别名的警告.代码基本归结为:
#include <type_traits>
std::aligned_storage<sizeof(int), alignof(int)>::type storage;
int main()
{
*reinterpret_cast<int*>(&storage) = 42;
}
Run Code Online (Sandbox Code Playgroud)
使用最新的GCC 7 RC进行编译:
$ g++ -Wall -O2 -c main.cpp
main.cpp: In function 'int main()':
main.cpp:7:34: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
*reinterpret_cast<int*>(&storage) = 42;
Run Code Online (Sandbox Code Playgroud)
(有趣的观察是,禁用优化时不会产生警告)
使用GCC 6进行编译完全没有警告.
现在我想知道,上面的代码肯定有类型 - 惩罚,毫无疑问,但是不是std::aligned_storage故意用这种方式?
例如,此处给出的示例代码通常不会对GCC 7发出警告,但仅仅是因为:
std::string 不知何故不受影响,std::aligned_storage 使用偏移量访问.通过改变std::string进int,消除抵消访问std::aligned_storage和删除无关的部分,你会得到:
#include <iostream>
#include <type_traits>
#include <string>
template<class T, std::size_t N>
class static_vector
{
// properly aligned uninitialized storage for N T's
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
std::size_t m_size = 0;
public:
// Access an object in aligned storage
const T& operator[](std::size_t pos) const
{
return *reinterpret_cast<const T*>(data/*+pos*/); // <- note here, offset access disabled
}
};
int main()
{
static_vector<int, 10> v1;
std::cout << v1[0] << '\n' << v1[1] << '\n';
}
Run Code Online (Sandbox Code Playgroud)
这会产生完全相同的警告:
main.cpp: In instantiation of 'const T& static_vector<T, N>::operator[](std::size_t) const [with T = int; unsigned int N = 10; std::size_t = unsigned int]':
main.cpp:24:22: required from here
main.cpp:17:16: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
return *reinterpret_cast<const T*>(data/*+pos*/);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
所以我的问题是 - 这是一个错误还是一个功能?
我无法回答是否确实存在由于别名而导致未定义行为的可能性,或者警告是否没有根据。我发现别名主题是一个相当复杂的雷区。
但是,我认为代码的以下变体消除了别名问题,而没有任何开销(并且可能更具可读性)。
#include <iostream>
#include <type_traits>
#include <string>
template<class T, std::size_t N>
class static_vector
{
// properly aligned uninitialized storage for N T's
union storage_t_ {
T item;
typename std::aligned_storage<sizeof(T), alignof(T)>::type aligned_member;
};
storage_t_ data[N];
std::size_t m_size = 0;
public:
// Access an object in aligned storage
const T& operator[](std::size_t pos) const
{
return data[0].item;
}
};
int main()
{
static_vector<int, 10> v1;
std::cout << v1[0] << '\n' << v1[1] << '\n';
}
Run Code Online (Sandbox Code Playgroud)
对于你的情况是否可以接受,我不能确定。
| 归档时间: |
|
| 查看次数: |
580 次 |
| 最近记录: |