C++ 交换包含非平凡可复制类型的`std::aligned_storage`实例-未定义的行为?
C++ 交换包含非平凡可复制类型的`std::aligned_storage`实例-未定义的行为?,c++,language-lawyer,swap,undefined-behavior,c++14,C++,Language Lawyer,Swap,Undefined Behavior,C++14,#包括 #包括 使用名称空间std; //非平凡可复制类型。 结构NTC { int x; NTC(int-mX):x(mX){} ~NTC(){cout在缓冲区中放置了一个非平凡的可复制类型之后直接访问该缓冲区的字节是一个非常糟糕的主意,但目前还没有定义 在交换为NTC后尝试访问缓冲区违反了别名规则[basic.lval]p10: 如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义: (10.1)——对象的动态类型 [……] 通过memcpy或等效程序复制普通可复制
#包括
#包括
使用名称空间std;
//非平凡可复制类型。
结构NTC
{
int x;
NTC(int-mX):x(mX){}
~NTC(){cout在缓冲区中放置了一个非平凡的可复制类型之后直接访问该缓冲区的字节是一个非常糟糕的主意,但目前还没有定义
在交换为NTC
后尝试访问缓冲区违反了别名规则[basic.lval]p10:
如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:
(10.1)——对象的动态类型
[……]
通过memcpy
或等效程序复制普通可复制类型意味着要保留动态类型。对于非普通可复制类型没有这种含义,因此在交换后,您不再有任何NTC
对象可访问。我最初读错了,可以立即修复,但hvd得到了它。感谢answer、 还有一些疑问-什么是动态类型?它是否只与多态对象相关(显然,多态对象也是不可复制的)?如果是,将存储在std::aligned_storage
实例中的T
类型强制为非多态类型(可能通过静态\u断言
)确保交换对齐的存储实例是安全的?@vittoriormeo对于左值,“动态类型”是左值引用的对象的类型。它在1.3.7中定义,并且它不仅适用于多态对象:给定struct A{};struct B:A{}B.A&A= B;,动态类型<代码> A<代码> >代码> B/COD>,但没有语言构造将使用该动态类型。@ VITTRORORMOOO对于一个有实际意义的例子,它可以用非平凡的可复制类型来打破,考虑piml习惯用法,但是考虑实现类型需要一个后置指针的情况。某些原因。如果像您这样交换缓冲区,即使类型没有任何虚拟函数,这也无法工作。因此UB出现在这里*static\u cast(static\u cast(&as1))
?(我们在这里创建了一个NTC*
,指向的不是NTC
?)或in1.~NTC()
我们在哪里使用它?有趣的是,我认为如果OP将指向as1
的指针存储为NTC*
并由new
返回,则调用std::swap
可能是未定义的行为(因为swap
得到了一个对它的引用,作为一个对齐的存储,以及唯一的地址别名要求——或者可能只有当我们得到一个指向它的指针时,嗯)@Yakk是个好问题。标准同时说“引用应该初始化为引用一个有效的对象或函数”([dcl.ref]p5)并给出了一个引用如何绑定到未初始化的int
变量([dcl.init.ref]p1)的示例。我不清楚引用的绑定是否有效。无论如何,析构函数调用肯定不是。
#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;
}