Why std::pair and std::tuple differ in size?

It is known that std::tuple (since c++11) is a generalization of std::pair. However, they exhibit some slight differences in some cases.

Consider the following code:

struct dummy {};

int main() {
    std::cout << sizeof(int) << std::endl;
    std::cout << sizeof(std::pair<int, dummy>) << std::endl;
    std::cout << sizeof(std::tuple<int, dummy>) << std::endl;
}

When compiling with g++ and libstdc++, the output might be 4, 8, 4. Why std::tuple<int, dummy> takes less space than std::pair<int, dummy>?

This is a nontrivial problem. Unlike C, empty structs (and classes) are supported in C++; however, they must take nonzero space (typically 1 byte) so that every instance of the empty struct has unique address.

The typical implementation of pair<T1, T2> is simply a struct with two members T1 first and T2 second. For std::pair<int, dummy>, it contains two members, of type int and dummy respectively. The total size is 5, however, due to padding, the pair actually takes 8 bytes.

Since the number of members of a tuple is variable, its implementation is more complex. In libstdc++, the tuple is implemented as double inheritance: _Tuple_impl<id, X, Y, Z> inherits _Head_base<id, X> and _Tuple_impl<id + 1, Y, Z>, and _Head_base<id, X> again inherits X if X is an empty non-final struct. In such case, _Head_base<id, X> is also empty and thus the compiler is allowed to perform Empty Base Optimization (EBO), that is, the empty base need not take up any space. That’s why std::pair<int, dummy> takes only 4 bytes.

发表评论

电子邮件地址不会被公开。 必填项已用*标注