假设您有一个可简单复制的类型,而不是聚合,并且不可简单构造:
struct Foo
{
Foo() = default;
Foo(int i)
: a(i)
{};
int a = 5;
};
Foo 不是一个聚合,因为它有一个用户声明的构造函数,它不是可简单构造的,因为它有用户定义的初始化程序,并且它是可简单复制和可破坏的。这不是一个简单的类型。
尝试通过 memcpy 隐式构造此类类型是否合法?
Foo* makeFooCopy(const Foo& src)
{
// Assume alignment isn't a problem
auto ptr = malloc(sizeof(Foo));
memcpy(ptr, &src, sizeof(Foo));
return reinterpret_cast<Foo*>(ptr);
}
cppreference 表示隐式生命周期类型“...至少有一个简单的合格构造函数和一个简单的、不可删除的析构函数”。 (聚合情况不适用于此处)。但我不清楚这里的“平凡的合格构造函数”是什么;它必须是默认构造函数(即,这只是说明该类型需要是普通默认可构造的),或者普通复制对象的能力就足够了吗?
激励问题是我们代码中的类似向量的类型;分析表明,在特定的用例中,我们的大量运行时间包括将可普通复制但不是普通默认可构造类型的连续容器复制到我们的类似向量类型中,该类型目前作为围绕 emplace_back 的循环实现。我们只想使用 memcpy 复制整个缓冲区,如下所示:
template<MemcpyableContainer C>
SpecialVectorType(const C& container)
{
resize(std::size(container));
memcpy(our_storage, std::addressof(*std::begin(container)), std::size(container) * sizeof(element_type))
}
但是我们的编译器没有优化调整大小中新调用的位置。我不清楚删除它们是否合法。
C++23 中添加了类型特征 std::is_implicit_lifetime。
这是相关草案中的实现p2674
template <typename T>
struct is_implicit_lifetime
: std::disjunction<
std::is_scalar<T>, std::is_array<T>, std::is_aggregate<T>,
std::conjunction<
std::is_trivially_destructible<T>,
std::disjunction<std::is_trivially_default_constructible<T>,
std::is_trivially_copy_constructible<T>,
std::is_trivially_move_constructible<T>>>> {};
毫无疑问,类
Foo
是一个隐式生命周期类型。它被明确定义为通过 memcpy
隐式创建此类对象。