【问题标题】:sizeof() on C++ Standard LibraryC++ 标准库上的 sizeof()
【发布时间】:2013-07-04 14:34:25
【问题描述】:

我很好奇并在一些 C++ 标准库类上应用了sizeof() 运算符。这是我观察到的:

int main() 
{
    vector<double> v1;
    set<double> s1;
    map<double,double> m1;

    stack<char> st;
    queue<char> q;

    vector<char>  v2;
    set<char> s2;
    map<char,char> m2;

    cout<<sizeof(v1)<<" "<<sizeof(s1)<<" "<<sizeof(m1)<<endl;
    cout<<sizeof(v2)<<" "<<sizeof(s2)<<" "<<sizeof(m2)<<endl;
    cout<<sizeof(q)<<" "<<sizeof(st)<<endl;
    return 0;
}

我的系统(64 位)上的输出是:

12 24 24
12 24 24
40 40

我知道std::set 使用红黑树来实现。因此,二叉树的每个节点都有两个指针(每个 8 个字节),值(8 个字节,总共 24 个)似乎没问题。

  1. std::map(也使用红黑树)有一个额外的密钥,但仍然是 24 字节?为什么?

  2. 为什么std::queuestd::stack 占用40 个字节,而std::vector 只占用12 个字节?

  3. 为什么chardouble不影响类的大小?是因为模板吗?

【问题讨论】:

  • sizeof 不是函数,而是 C++ 语言中定义的运算符和关键字。
  • 你为什么会期待sizeof(container)==sizeof(node)
  • 为什么会这样?例如,容器可能只是指向根节点的指针的包装器。
  • @banarun:为什么?节点不存储在容器对象本身中。它们是动态存储的,并在容器对象中引用(可能通过指针)。
  • 您可能拥有 64 位系统,但您使用的是 32 位编译器。

标签: c++ stl std


【解决方案1】:

这些类的实现是一个黑盒子,没有办法知道它们包含什么数据或私有成员。这完全取决于实施。

了解对象实例中所有字节的唯一方法是阅读源代码。

【讨论】:

  • 无论是私有成员还是公共成员,sizeof() 不告诉类的大小吗?
  • @banarun 是的,sizeof 返回所有成员的大小,但您不知道它们是什么。并且仅仅因为一个类的大小为 24 字节并不意味着它有 3 个指针。
【解决方案2】:

sizeof 运算符将为您提供类型的大小。

现在,如果我要在这里制作一个非常简化的 std::vector&lt;T&gt; 版本(请注意,这并没有真正的实现做任何事情,而且它过于简化而无法真正工作 - 我正在跳过超过你真正需要的很多位):

template<typename T>
class vector<T>
{
   public:
      typedef size_t size_type;
   private:
     T* mdata;
     size_type msize;
     size_type mreserved;
   public:
     vector() { mreserved = msize = 0; mdata = 0; }
     vector(size_type sz) { msize = 0; mreserved = sz; mdata = new T[sz](); }
     void push_back(const T& v) 
     { 
        if (msize + 1 > mreserved) grow(mreserved * 2);
        mdata[msize+1] = v;
        msize++;
     }
     size_type size() const { return msize; }
     // bunch of other public functions go here. 
   private:
     void grow(size_type newsize)
     {
        if (newsize < 8) newsize = 8;
        T* newdata = new T[newsize]; 
        for(size_type i = 0; i < msize; i++) newdata[i] = mdata[i];
        swap(mdata, newdata);
        delete [] mdata;
        mreserved = newsize;
     }
  };

如您所见,无论存储的数据集有多大,实际类的大小都是相同的(它包含相同的大小和数量的元素)。换句话说,sizeof(vector&lt;int&gt;) 是不变的。 mdata 后面存储的数据大小当然会发生变化,但 sizeof 不知道(无法知道)这一点。

【讨论】:

    【解决方案3】:

    此示例源代码将为您提供思路:

    struct A
    {
        int* p; //4 bytes
        A(int n)
        {
            p = new int[n];
        }  
    };
    
    int main()
    {
        A x1(10);   
        A x2(100);  
        cout << boolalpha << (sizeof(x1) == sizeof(x2)); //prints true
    }
    

    原因是 A 只包含一个指针。指针的大小始终相同(通常为 4)。指针指向什么并不重要——1000 或 1000000 的动态数组。它仍然是 4。

    Char 或 double 不会影响大小,因为指向 char 的指针与指向 double 的指针具有相同的大小。

    对于一个 std::array,它实际上包含一个数组,而不是一个指针,这些很重要(数组类型和大小):

    cout << boolalpha << ((sizeof(std::array<int, 10>) == sizeof(std::array<int, 11>)); //false!
    cout << boolalpha << ((sizeof(std::array<int, 10>) == sizeof(std::array<long double, 10>)); //false!
    

    【讨论】:

      【解决方案4】:

      重要的是要记住sizeof 在编译时进行评估:所以它在任何意义上都不是动态的。

      它的工作是返回类/结构/普通旧数据的大小;没有别的。

      这就是为什么它总是为您的向量、集合和地图提供相同的结果。

      【讨论】:

        【解决方案5】:

        您似乎假设容器类的大小可以随着消耗的元素数量而增加,但这实际上是不可能的,因为所有类型都有固定的大小。

        相反,元素是使用动态分配间接存储的;
        sizeof 不会向您透露此信息

        sizeof给你的唯一信息是在容器的构建和管理中使用了多少指针、计数器、标志和其他元数据;这种细节是从你身上抽象出来的,你永远不应该试图合理化它。

        【讨论】:

          猜你喜欢
          • 2014-12-26
          • 2020-01-05
          • 1970-01-01
          • 2011-06-21
          • 1970-01-01
          • 2011-06-16
          • 1970-01-01
          • 1970-01-01
          • 2011-03-13
          相关资源
          最近更新 更多