为什么 std::tuple 不能<int>被简单复制?

Why can't std::tuple<int> be trivially copyable?

本文关键字:复制 gt 简单 lt std tuple 不能 为什么 int      更新时间:2023-10-16

使用此在线编译器构建,以下代码:

#include <iostream>
#include <type_traits>
#include <tuple>
int main() {
    std::cout << std::is_trivially_copyable<std::tuple<int>>::value << std::endl;
    std::cout << std::is_trivially_copyable<std::pair<int, int>>::value << std::endl;
    std::cout << std::is_trivial<std::tuple<int>>::value << std::endl;
    std::cout << std::is_trivial<std::pair<int, int>>::value << std::endl;
    return 0;
}

输出:

0
0
0
0

我在使用Visual Studio 2015时也得到了同样的结果。

为什么会这样?POD类型的std::tuple,更不用说简单的std::pair,不能被琐碎地复制,有什么正当的理由吗?我认为它们的实现提供了一些自定义赋值运算符,但它们与编译器生成的默认版本有何不同?

就琐碎的可复制性而言,让pair头疼的是,标准不要求复制/移动赋值运算符是琐碎的。该标准明确声明复制/移动构造函数是默认的,但对于赋值则不是这样。一个实现也可以默认它们,但标准并不要求这样做

没有什么好的理由可以解释为什么标准不要求它。但它没有。

对于tuple来说,事情要复杂得多。许多tuple实现基于具有合适大小/对齐的存储缓冲区,并使用放置new来构造该缓冲区内的各个成员。这一切都很好,但这样的类型必须实现手动复制/移动构造函数,因为它必须调用每个类型的复制/移动构造器。即使它知道它们都是微不足道的可复制性,并通过memcpy复制它们,这仍然是一个手动操作。这使它失去了微不足道的可复制性。

现在,有一些tuple的实现,如果类型是平凡可复制的,那么它们可能是平凡可拷贝的。但没有要求以这种方式来实施它们。如果所有类型都是可复制的,那么要求它们以一种方式实现自己,而在其他情况下以不同的方式实现它们,这将使tuple实现非常复杂。

因为std::tuple具有复制/移动ctor和赋值运算符,所以它使类不具有可复制性。

参见cpp参考:

一个微不足道的可复制类是

Has no non-trivial copy constructors (this also requires no virtual functions or virtual bases)
Has no non-trivial move constructors
Has no non-trivial copy assignment operators
Has no non-trivial move assignment operators
Has a trivial destructor

std::tuple具有以上所有的构造函数和赋值运算符。