为什么 std::tuple<int> 不能简单复制?
Why can't std::tuple<int> be trivially copyable?
用this online compiler构建,代码如下:
#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 相同的结果。
为什么会这样? std::tuple
的 POD 类型,更不用说简单的 std::pair
,是否有正当理由不能被简单地复制?我假设它们的实现提供了一些自定义赋值运算符,但它们与编译器生成的默认版本有何不同?
因为 std::tuple
有 copy/move 构造函数和赋值运算符,它使得 class 不可平凡地复制。
A trivially copyable class is a class that
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
具有上述所有构造函数和赋值运算符。
就琐碎的可复制性而言,绊倒 pair
的是标准不 要求 copy/move 赋值运算符是琐碎的.该标准明确声明 copy/move 构造函数 是默认的,但赋值并非如此。实现也可以默认它们,但标准不需要它。
没有充分的理由说明标准不要求它。但事实并非如此。
对于tuple
,事情要复杂很多。许多 tuple
实现基于具有右侧 size/alignment 的存储缓冲区,并使用放置 new
在该缓冲区中构造各个成员。这很好,但是这样的类型必须实现手动 copy/move 构造函数,因为它必须调用每个类型的 copy/move 构造函数。即使它知道它们都是简单可复制的并通过 memcpy
复制它们,这仍然是一个手动操作。这使它失去了可复制性的资格。
现在,有 tuple
的实现,如果类型是可平凡复制的,则可以是平凡可复制的。但是没有要求以这种方式实施它们。如果所有类型都可以轻松复制,则要求它们以一种方式实现自己,否则会使 tuple
实现变得非常复杂,否则以不同的方式实现它们。
用this online compiler构建,代码如下:
#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 相同的结果。
为什么会这样? std::tuple
的 POD 类型,更不用说简单的 std::pair
,是否有正当理由不能被简单地复制?我假设它们的实现提供了一些自定义赋值运算符,但它们与编译器生成的默认版本有何不同?
因为 std::tuple
有 copy/move 构造函数和赋值运算符,它使得 class 不可平凡地复制。
A trivially copyable class is a class that
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
具有上述所有构造函数和赋值运算符。
就琐碎的可复制性而言,绊倒 pair
的是标准不 要求 copy/move 赋值运算符是琐碎的.该标准明确声明 copy/move 构造函数 是默认的,但赋值并非如此。实现也可以默认它们,但标准不需要它。
没有充分的理由说明标准不要求它。但事实并非如此。
对于tuple
,事情要复杂很多。许多 tuple
实现基于具有右侧 size/alignment 的存储缓冲区,并使用放置 new
在该缓冲区中构造各个成员。这很好,但是这样的类型必须实现手动 copy/move 构造函数,因为它必须调用每个类型的 copy/move 构造函数。即使它知道它们都是简单可复制的并通过 memcpy
复制它们,这仍然是一个手动操作。这使它失去了可复制性的资格。
现在,有 tuple
的实现,如果类型是可平凡复制的,则可以是平凡可复制的。但是没有要求以这种方式实施它们。如果所有类型都可以轻松复制,则要求它们以一种方式实现自己,否则会使 tuple
实现变得非常复杂,否则以不同的方式实现它们。