Modern C++利用工具快速理解std::tuple的实现原理

1. tuple简介

std::tuple 是 C++ 标准库中的一个模板类,它用于存储固定大小的、类型可能不同的值的集合。与数组或标准库中的其他序列容器(如 std::vector、std::list)不同,std::tuple 可以包含不同类型的元素,并且它的大小在编译时是固定的。

我们曾经在《Modern C++ std::tuple的size》中提出一个sizeof(std::tuple)的问题,不过要弄懂这个问题需要两步:先理解tuple的基本数据结构,再弄懂一些关于存储的优化。本节着重第一步。

2. preview

没有时间的同学看下预览就可以退出了哈。
Modern C++利用工具快速理解std::tuple的实现原理_第1张图片

3. 学习方法

要理解tuple的实现,可以读源码,在我机器上源码在/usr/include/c++/8/tuple。但现代人就要用现代化工具,我想先用chatGPT了解下大概,再用GDB打印一个tuple实例的继承体系。

4. 问询助手ChatGPT

mzhai: Tell me the implementation of std::tuple
Modern C++利用工具快速理解std::tuple的实现原理_第2张图片
大概意思:

  1. 用了元编程
  2. 用了递归和模板特化

Chat GPT还贴心的给了一个简单的实现帮我们理解:

// Simplified Tuple Implementation (Conceptual)
template <typename... Types>
class Tuple;

template <>
class Tuple<> {};  // Base case for an empty tuple

template <typename Head, typename... Tail>
class Tuple<Head, Tail...> {
public:
    Tuple(Head head, Tail... tail) : head_(head), tail_(tail...) {}

    // Access functions
    Head& getHead() { return head_; }
    const Head& getHead() const { return head_; }

    Tuple<Tail...>& getTail() { return tail_; }
    const Tuple<Tail...>& getTail() const { return tail_; }

private:
    Head head_;
    Tuple<Tail...> tail_;
};

// Example usage:
int main() {
    Tuple<int, double, char> myTuple(42, 3.14, 'A');
    std::cout << myTuple.getHead() << std::endl;  // Accessing the first element
    std::cout << myTuple.getTail().getHead() << std::endl;  // Accessing the second element

    return 0;
}

5. GDB打印继承体系

先写个简单的CPP程序

#include 
using namespace std;
int main(){
std::tuple<char, int,double> t = {'a', 1, 2.2}}

编译后GDB调试过std::tuple那一行。
打印t

(gdb) p t
$1 = std::tuple containing = {[1] = 97 'a', [2] = 1, [3] = 2.2000000000000002}

GDB隐藏了具体的数据结构,只打印了程序员关心的数值。是时候启用命令ptype了:

ptype 是 GNU Debugger (GDB) 中的一个命令,用于打印出数据类型的信息。当你在调试过程中,需要了解某个变量、表达式或者类型的数据结构时,ptype 命令会非常有用。

(gdb) ptype t
type = class std::tuple<char, int, double> : public std::_Tuple_impl<0, char, int, double> {
  public:
    tuple(const std::tuple<char, int, double> &);
    tuple(std::tuple<char, int, double> &&);
    std::tuple<char, int, double> & operator=(const std::tuple<char, int, double> &);
    std::tuple<char, int, double> & operator=(std::tuple<char, int, double> &&);
    void swap(std::tuple<char, int, double> &);
}

可见tuple继承自std::_Tuple_impl<0, char, int, double>,继续ptype std::_Tuple_impl<0, char, int, double>:

(gdb) ptype std::_Tuple_impl<0, char, int, double>
type = struct std::_Tuple_impl<0, char, int, double> : public std::_Tuple_impl<1, int, double>
        , private std::_Head_base<0, char, false> {
  public:
  ...
}

std::_Tuple_impl<0, char, int, double>又继承自两个类:std::_Tuple_impl<1, int, double>,std::_Head_base<0, char, false>。一路ptype下去,我们就会得到完整的继承图。
Modern C++利用工具快速理解std::tuple的实现原理_第3张图片
链式继承,且每一层都有一个数据_M_head_Impl, 就像洋葱一样一层层的,每层的数据都能打印出来:

(gdb) p t.std::_Tuple_impl<0, char, int, double>::_M_head_impl
$9 = 97 'a'
(gdb) p t.std::_Tuple_impl<1, int, double>::_M_head_impl
$10 = 1
(gdb) p t.std::_Tuple_impl<2, double>::_M_head_impl
$11 = 2.2000000000000002

6. 结尾

好了,这就是std::tuple的庐山真面目,是不是学的很快?
最后,不知道有人注意到上面类模板参数中有很多false/true没有?这些就是sizeof(tuple)变小的答案,我们下节见~

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