交换包含非一般可复制类型的“std::aligned_storage”实例-未定义的行为



视频链接

#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样式数组的typedef
  • std::swap自C++11以来就有C样式数组的重载
  • 该重载调用std::swap_ranges,它交换数组中的每个元素
  • 因此,交换两个NTC0实例应该逐个元素地交换它们的内容

我在这些新的假设中犯了什么错误吗

在一个不常见的可复制类型被放入缓冲区后直接访问缓冲区的字节是一个非常糟糕的主意,但还没有定义。

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

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

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

[….]

通过memcpy或等效程序复制一个普通的可复制类型是为了保留动态类型。对于不常见的可复制类型没有这样的含义,所以在交换之后,您就不再有任何NTC对象可以访问了。

最新更新