Ada*_*dam 5 c++ strict-aliasing
我正在读关于reinterpret_cast及其别名规则的说明(http://en.cppreference.com/w/cpp/language/reinterpret_cast).
我写了那段代码:
struct A
{
int t;
};
char *buf = new char[sizeof(A)];
A *ptr = reinterpret_cast<A*>(buf);
ptr->t = 1;
A *ptr2 = reinterpret_cast<A*>(buf);
cout << ptr2->t;
Run Code Online (Sandbox Code Playgroud)
我认为这些规则不适用于此:
在我看来,这段代码是不正确的.我对吗?代码是否正确?
另一方面,连接功能(man 2 connect)和struct sockaddr怎么样?
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
Run Code Online (Sandbox Code Playgroud)
例如.我们有struct sockaddr_in,我们必须将它转换为struct sockaddr.以上规则也不适用,这个演员是不正确的?
是的,它是无效的,但不是因为你正在将a转换char*
为A*
:它是因为你没有获得A*
实际指向的a ,A*
并且正如你所确定的那样,没有任何类型的别名选项适合.
你需要这样的东西:
#include <new>
#include <iostream>
struct A
{
int t;
};
char *buf = new char[sizeof(A)];
A* ptr = new (buf) A;
ptr->t = 1;
// Also valid, because points to an actual constructed A!
A *ptr2 = reinterpret_cast<A*>(buf);
std::cout << ptr2->t;
Run Code Online (Sandbox Code Playgroud)
现在输入别名根本不会进入它(虽然继续阅读因为还有更多要做!).
实际上,这还不够.我们还必须考虑调整.虽然上面的代码似乎可以工作,但是要完全安全,你需要将它放置new
到一个正确对齐的存储区域,而不仅仅是一个偶然的块char
.
标准库(从C++ 11开始)使我们std::aligned_storage
能够这样做:
using Storage = std::aligned_storage<sizeof(A), alignof(A)>::type;
auto* buf = new Storage;
Run Code Online (Sandbox Code Playgroud)
或者,如果您不需要动态分配它,只需:
Storage data;
Run Code Online (Sandbox Code Playgroud)
然后,做你的位置 - 新:
new (buf) A();
// or: new(&data) A();
Run Code Online (Sandbox Code Playgroud)
并使用它:
auto ptr = reinterpret_cast<A*>(buf);
// or: auto ptr = reinterpret_cast<A*>(&data);
Run Code Online (Sandbox Code Playgroud)
所有内容看起来像这样:
#include <iostream>
#include <new>
#include <type_traits>
struct A
{
int t;
};
int main()
{
using Storage = std::aligned_storage<sizeof(A), alignof(A)>::type;
auto* buf = new Storage;
A* ptr = new(buf) A();
ptr->t = 1;
// Also valid, because points to an actual constructed A!
A* ptr2 = reinterpret_cast<A*>(buf);
std::cout << ptr2->t;
}
Run Code Online (Sandbox Code Playgroud)
即便如此,自C++ 17以来,这有点复杂; 有关更多信息,请参阅相关的cppreference页面并注意std::launder
.
当然,这整件事情似乎是人为的,因为你只需要一个A
,因此不需要数组形式; 事实上,你首先要创建一个沼泽标准A
.但是,假设buf
实际上实际上更大,并且你正在创建一个分配器或类似的东西,这是有道理的.