简而言之,这让我更加敬重图书馆实现者们。他们必须遵循的规则以实现对std::tuple
的优化是令人惊叹的,一旦你开始思考如何实现这个过程。
自然地,我进行了一些尝试,看看情况如何。
设置:
struct Empty {};
template <class T> auto print_mem(const T& obj)
{
cout << &obj << " - " << (&obj + 1) << " (" << sizeof(obj) << ")" << endl;
}
测试内容:
int main() {
std::tuple<int> t_i;
std::tuple<Empty> t_e;
std::tuple<int, Empty, Empty> t_iee;
std::tuple<Empty, Empty, int> t_eei;
std::tuple<int, Empty, Empty, int> t_ieei;
cout << "std::tuple<int>" << endl;
print_mem(t_i);
cout << endl;
cout << "std::tuple<Empty>" << endl;
print_mem(t_e);
cout << endl;
cout << "std::tuple<int, Empty, Empty" << endl;
print_mem(t_iee);
print_mem(std::get<0>(t_iee));
print_mem(std::get<1>(t_iee));
print_mem(std::get<2>(t_iee));
cout << endl;
cout << "std::tuple<Empty, Empty, int>" << endl;
print_mem(t_eei);
print_mem(std::get<0>(t_eei));
print_mem(std::get<1>(t_eei));
print_mem(std::get<2>(t_eei));
cout << endl;
print_mem(t_ieei);
print_mem(std::get<0>(t_ieei));
print_mem(std::get<1>(t_ieei));
print_mem(std::get<2>(t_ieei));
print_mem(std::get<3>(t_ieei));
cout << endl;
}
结果如下:
std::tuple<int>
0xff83ce64 - 0xff83ce68 (4)
std::tuple<Empty>
0xff83ce63 - 0xff83ce64 (1)
std::tuple<int, Empty, Empty
0xff83ce68 - 0xff83ce6c (4)
0xff83ce68 - 0xff83ce6c (4)
0xff83ce69 - 0xff83ce6a (1)
0xff83ce68 - 0xff83ce69 (1)
std::tuple<Empty, Empty, int>
0xff83ce6c - 0xff83ce74 (8)
0xff83ce70 - 0xff83ce71 (1)
0xff83ce6c - 0xff83ce6d (1)
0xff83ce6c - 0xff83ce70 (4)
std::tuple<int, Empty, Empty, int>
0xff83ce74 - 0xff83ce80 (12)
0xff83ce7c - 0xff83ce80 (4)
0xff83ce78 - 0xff83ce79 (1)
0xff83ce74 - 0xff83ce75 (1)
0xff83ce74 - 0xff83ce78 (4)
Ideone链接
我们从一开始就可以看到,
(需要继续翻译的内容不明确,请提供更多上下文。)
sizeof(std:tuple<Empty>) == 1 (because the tuple cannot be empty)
sizeof(std:tuple<int>) == 4
sizeof(std::tuple<int, Empty, Empty) == 4
sizeof(std::tuple<Empty, Empty, int) == 8
sizeof(std::tuple<int, int>) == 8
sizeof(std::tuple<int, Empty, Empty, int>) == 12
我们可以看到,在某些情况下确实没有为
Empty
保留空间,但在某些情况下会分配
1字节
的
Empty
(其余是填充)。 当
Empty
元素是最后一个元素时,它看起来可能是
0
。
通过使用
get
获得的地址仔细检查,我们可以看到即使那些
Empty
的地址(在
int
元素内)似乎在
内部,也不会有两个
Empty
元组元素具有相同的地址(与上述规则一致)。而且,
Empty
元素的任何地址都不在容器元组的内存位置之外。
这让我想到:如果我们有比
sizeof(int)
更多的末尾
Empty
,那会增加元组的
sizeof
吗? 确实会增加。
sizeof(std::tuple<int>)
sizeof(std::tuple<int, Empty>)
sizeof(std::tuple<int, Empty, Empty>)
sizeof(std::tuple<int, Empty, Empty, Empty>)
sizeof(std::tuple<int, Empty, Empty, Empty, Empty>)
sizeof(std::tuple<int, Empty, Empty, Empty, Empty, Empty>)
最后一点:对于Empty
元素来说,拥有“幽灵”地址是可以的(它们似乎与int
元素共享内存)。由于Empty
是一个……好吧……空类,它没有非静态数据成员,这意味着为它们获取的内存无法访问。