c++ - cppreference 上 std::uninitialized_default_construct 示例中的未定义行为?

标签 c++ language-lawyer pointer-arithmetic placement-new

在他们的 examplestd::uninitialized_default_construct :

    struct S { std::string m{ "Default value" }; };
 
    constexpr int n {3};
    alignas(alignof(S)) unsigned char mem[n * sizeof(S)];
 
    try
    {
        auto first {reinterpret_cast<S*>(mem)};
        auto last {first + n};  // (1)**********
 
        std::uninitialized_default_construct(first, last);

        // (2)**********
        for (auto it {first}; it != last; ++it) {
            std::cout << it->m << '\n';
        }
 
        std::destroy(first, last);
    }
    catch(...)
    {
        std::cout << "Exception!\n";
    }
 
    // Notice that for "trivial types" the uninitialized_default_construct
    // generally does not zero-fill the given uninitialized memory area.
    int v[] { 1, 2, 3, 4 };
    const int original[] { 1, 2, 3, 4 };
    std::uninitialized_default_construct(std::begin(v), std::end(v));

    // (3)**********
    // for (const int i : v) { std::cout << i << ' '; }
    // Maybe undefined behavior, pending CWG 1997.
我有三个问题。 (标记为 ********** )
  • Sunsigned char不是 指针互变 , 将 last指向 mem 的结尾?这里是指针算术未定义行为吗?
  • std::launder 需要在这里制作 firstlast实际上指向S ?例如first = std::launder(first); last = first + n;
  • 打印 v 的元素真的是未定义的行为吗? ? CWG 1997说说 unsigned char[]存储,但上面的例子已经初始化 vint s。
  • 最佳答案

  • unsigned char是另一种说法 1 byte ,因此分配是针对 struct S 的大小进行的(以字节为单位)乘以元素数 n . mem类型为 unsigned char [] ,因此,根据 [conv.array]/1它相当于 unsigned char *它指向数组中的第一个元素,根据 [expr.reinterpret.cast]/4 reinterpret_cast将其转换为 struct S*这将导致 first ,声明为 auto要创建为 struct S* ,因此该语句可与 C 互换形式:
    struct S* first = (struct S*) &mem
    
    first解析为 struct S* ,因此 last也将被解析为相同的类型,指针算术将正常工作。
  • 不需要std::launder自声明auto first {reinterpret_cast<S*>(mem)};已经初始化了指向 mem 中第一个元素的指针, 下一个带有指针算法的语句已经设置了 last到第三个元素。
  • 我认为这是正确的,这是自 CWG 1997 起未定义的行为. int [] ,这是 v 的类型, 没有默认构造函数,因此 v无法初始化。根据定义,这些值将保持未确定状态。令人困惑的部分是 v 的元素已经被编译器初始化为 1, 2, 3, 4 ,因此期望该值将被保留(因为它们已经在内存位置中),但是从标准的角度来看,不确定是否 v将在 std::uninitialized_default_construct(std::begin(v), std::end(v)) 之后保持此值.
  • 关于c++ - cppreference 上 std::uninitialized_default_construct 示例中的未定义行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66947790/

    相关文章:

    c - 保证指向标准函数的指针不相等?

    c++ - 未初始化的引用是否为零初始化和未初始化的标量默认初始化?

    c++ - 指针运算 Visual Studio C++

    c++ - 如何重载运算符 [][]

    c++ - GCC 和 clang 关于 "typename"关键字的分歧

    c++ - 无法使用 boost::python 更改传递给 python 函数的对象

    c - 使用指针时的奇怪行为

    c - 使用指针操作打印输入的字符串

    c++ - 在opencv中读取视频文件的连续图像

    c++ - 不使用 boost::asio::ip::tcp::socket 调用移动构造函数