交换包含非平凡可复制类型的`std :: aligned_storage`实例 - 未定义的行为?

时间:2015-03-28 13:56:12

标签: c++ language-lawyer swap undefined-behavior c++14

ideone link

#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;
}

以上代码是否未定义行为?

这就是我认为发生的事情:

  • NTC是一种非平凡的可复制类型。
  • 我创建了两个适合存储NTC个对象的内存位置(std::aligned_storage)。
  • 我将两个NTC实例直接构建到内存位置。
  • std::aligned_storage instances are PODTypes
      

    这意味着该类型与C编程语言中使用的类型兼容,可以使用C库函数进行操作:它可以使用std :: malloc创建,可以使用std :: memmove等进行复制,并且可以用二进制形式直接与C库交换。

  • 由于对齐的存储实例是POD类型,我应该被允许移动/交换/复制它们。
  • 交换对齐的存储实例意味着从对齐的存储A中获取所有字节,并将它们与对齐存储B中的所有字节进行交换
  • 这样做不会调用内部存储的NTC对象的析构函数/复制构造函数。

我的任何一点不正确?如果确实发生未定义的行为,程序的哪个部分会发生?为什么?


可能正确/不正确的信息(gathered from a deleted answer):

我是否在这些新假设中犯了错误?

1 个答案:

答案 0 :(得分:5)

在放入非平凡可复制类型之后直接访问缓冲区的字节是一个非常糟糕的主意,但尚未定义。

在作为NTC交换后尝试访问缓冲区违反了别名规则,[basic.lval] p10:

  

如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:

     

(10.1) - 对象的动态类型,

     

[...]

隐含通过memcpy或等效类型复制一个简单的可复制类型来保留动态类型。对于非平凡的可复制类型没有这样的含义,因此在交换之后,您不再有任何NTC个对象可供访问。