在他们的 example的 std::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.
我有三个问题。 (标记为 ********** )S
和 unsigned char
不是 指针互变 , 将 last
指向 mem
的结尾?这里是指针算术未定义行为吗? first
和 last
实际上指向S
?例如first = std::launder(first); last = first + n;
v
的元素真的是未定义的行为吗? ? CWG 1997说说 unsigned char[]
存储,但上面的例子已经初始化 v
与 int
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
到第三个元素。 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/