视频链接
#include <iostream>
#include <type_traits>
using namespace std;
// Non-trivially-copyable type.
struct NTC
{
int x;
NTC(int mX) : x(mX) { }
~NTC() { cout << "boop." << x << endl; }
};
int main()
{
using AS = aligned_storage_t<sizeof(NTC), alignof(NTC)>;
// Create two `std::aligned_storage` instances
// and "fill" them with two "placement-new-constructed"
// `NTC` instances.
AS as1, as2;
new (&as1) NTC{2};
new (&as2) NTC{5};
// Swap the `aligned_storages`, not their contents.
std::swap(as1, as2);
// Explicitly call `~NTC()` on the contents of the
// aligned storage instances.
NTC& in1{*static_cast<NTC*>(static_cast<void*>(&as1))};
NTC& in2{*static_cast<NTC*>(static_cast<void*>(&as2))};
in1.~NTC();
in2.~NTC();
return 0;
}
以上代码是否有未定义的行为
以下是我认为正在发生的事情:
- CCD_ 1是一个非平凡的可复制类型
- 我正在创建两个适合存储
NTC
对象(std::aligned_storage
)的内存位置 - 我将两个
NTC
实例直接构造到内存位置中 std::aligned_storage
实例是POD类型。这意味着该类型与C编程语言中使用的类型兼容,可以使用C库函数进行操作:它可以用std::malloc创建,可以用std::memmove复制,等等,并且可以以二进制形式直接与C库交换。
- 由于对齐的存储实例是POD类型,因此应该允许我四处移动/交换/复制它们
- 交换对齐的存储实例意味着从对齐的存储A中获取所有字节,并与对齐的存储B中的所有字节进行交换
- 这样做不会调用内部存储的
NTC
对象的析构函数/副本构造函数
我的任何观点是否不正确?如果未定义的行为确实发生,它会发生在程序的哪个部分?为什么?
新的潜在正确/不正确的信息(从已删除的答案中收集):
std::aligned_storage
在很大程度上只是C样式数组的typedefstd::swap
自C++11以来就有C样式数组的重载- 该重载调用
std::swap_ranges
,它交换数组中的每个元素 - 因此,交换两个
NTC
0实例应该逐个元素地交换它们的内容
我在这些新的假设中犯了什么错误吗
在一个不常见的可复制类型被放入缓冲区后直接访问缓冲区的字节是一个非常糟糕的主意,但还没有定义。
在作为NTC
进行交换后尝试访问缓冲区违反了别名规则[basic.lval]p10:
如果程序试图通过以下类型以外的glvalue访问对象的存储值,则行为未定义:
(10.1)——对象的动态类型,
[….]
通过memcpy
或等效程序复制一个普通的可复制类型是为了保留动态类型。对于不常见的可复制类型没有这样的含义,所以在交换之后,您就不再有任何NTC
对象可以访问了。