Modern C++ sizeof(std::tuple)的秘密及实现代码解读

1. 前言

我们曾经至少四篇帖子或多或少的提到过std::tuple的原理及占用空间大小:

  1. Modern C++ std::unique_ptr的实现原理
  2. Modern C++ std::tuple的size
  3. Modern C++利用工具快速理解std::tuple的实现原理
  4. GDB调试技巧实战–自动化画出类关系图

但是,当初在第一篇中提出的size的问题还悬而未决,今天我将着重讲这一块,同时也会讲一些tuple的实现代码。

2. 类继承 VS 类has-a

2.1 一般继承与有一个父对象

考虑下面的两片代码:

struct Base {
   
	int i;
}; 
 
struct Derived1 : Base
{
   
    int j;
};
struct Base {
   
	int i;
}; 
 
struct Derived1
{
   
	Base b;
    int j;
};

本质上没有什么区别,第一种是继承Base, 也相当于has a Base。它们的sizeof大小也相同。
加强训练下,猜下下面的程序的输出???:

#include
#include 
using namespace std;


struct Base {
   
	int i;
}; // empty class

struct Derived1 : Base
{
   
    int i;
};

struct Derived2 : Base
{
   
    int i;
};

struct Derived3 : Derived2, Derived1
{
   
};

int main()
{
   
	Derived3 d;
	std::cout<<sizeof(d)<<std::endl;
}

我没有给初始化,所以i的值比较随机,这反而能看出我们真的有4个i, 特别是Base.i有两个:

(gdb) p d
$1 = {
   <Derived2> = {
   <Base> = {
   i = -10544}, i = 32767}, <Derived1> = {
   <Base> = {
   i = 0}, i = 0}, <No data fields>}

2.2 继承空类 VS 有一个空类对象

但是,如果把Base换成空类哪?如果没有优化,第一种情况还相当于has a Base其大小是1,加上一个int总共8字节(有对其)。但历史没有假设,标准还偏偏允许有优化:Empty base optimization
继承的情况大小为4字节,比has a情况少用4个字节!

2.3 std::tuple中放空类对象 – 继承空类

一言以蔽之:std::tuple正是用了继承而非has a 而节约的空间。
我们举个例子,就举《Modern C++ std::unique_ptr的实现原理》中的例子吧,std::unique_ptr的本质是std::tuple, 它的大小是指针的大小8,而不是16. 写个程序验证一下:

#include
#include 
#include 
using namespace std;

int main()
{
   
	int i=5;
	std::tuple<int*

你可能感兴趣的:(modern,C++,c++,modern,c++,tuple,sizeof,metaprogramming)