【发布时间】:2018-07-15 02:44:01
【问题描述】:
trivial class 可以简单地复制并具有 trivial default constructor(trivial type 是其中之一,或者是类似工作的内置类)。
由于 you can use memcpy 复制普通类型的对象,并且由于 default-initializing 普通类型不会更改表示中的任何字节¹,以下代码(使用 C++20 概念)是否正确初始化了传入的对象?
#include <cstdlib>
#include <cstring>
#include <new>
#include <type_traits>
template <typename T>
T* copy_trivial(T orig) requires std::is_trivial_v<T>
{
void* buf = std::aligned_alloc(alignof(T), sizeof(T));
// Note the order of these statements
std::memcpy(buf, &orig, sizeof(T));
return new(buf) T;
}
(Compiler Explorer,提供了几个实例化)
看起来这段代码可以工作,因为会有一个具有正确对象表示的初始化对象。但是,考虑到在初始化之后什么都没有发生,那么该对象是否会改为具有indeterminate value²?
¹ 未在单个位置指定,但默认初始化的链接过程调用构造函数,该构造函数必须为implicitly defined;隐式定义的构造函数default-initializes all the members and bases;并且对于内置的平凡类型,该递归在no initialization is performed 处触底。
²[expr.new]p18.1 中的注释说它会,但注释是非规范性的,这似乎仅适用于非放置new。
【问题讨论】:
-
注意:这个问题的灵感来自this one,但我已经稍微简化了它以避免
realloc的复杂性。 -
有趣的问题,但我很好奇:以这种方式构造代码有什么好处,而不是先调用placement
new,然后是memcpy? -
@JohnZwinck 样本中的内存是由
malloc获得的。如果它是由realloc(或可能用于 C 代码的其他函数)获得的,那么复制将在有机会进行放置new之前发生。
标签: c++ initialization language-lawyer