【问题标题】:Why does a vector have the same size when I add elements to it?为什么当我向它添加元素时,向量具有相同的大小?
【发布时间】:2016-12-22 16:21:08
【问题描述】:

我有这个 C++ 结构:

typedef unsigned long T;

struct Node {
    T index;
    T length;
    Node(): index(0), length(0), next(0) {}
    Node(const T &ind, const T &len): index(ind), length(len), next(0) {}
    vector<Node*> next;
};

我正在尝试找出 next 将占用多少内存。我知道它最多有五个元素。所以这就是我要做的:

int main(int argc, const char * argv[]) {

    Node n;
    Node* x = new Node(3, 4);

    cout << "An empty vector of pointers: " << sizeof(n.next) << " bytes\n";

    // Add five elements
    for(int i = 0; i < 5; i++)
        n.next.push_back(x);

    cout<< "New size of the vector of pointers: " << n.next.size() << " elements\n";
    cout<< "New size of the vector of pointers: " << sizeof(n.next)  << " bytes\n";

    return 0;
}

这是我的输出:

An empty vector of pointers: 24 bytes
New size of the vector of pointers: 5 elements
New size of the vector of pointers: 24 bytes

我的问题:一个空向量怎么可能占用 24 个字节,但其中包含 5 个元素的同一个向量仍然占用 24 个字节?不应该占用更多内存吗?比如 *24 + 5 * sizeof(Node*)*?

【问题讨论】:

  • int* x = new int[1]; int* y = new int[100]。想一想,为什么 sizeof(x) == sizeof(y),即使它们指向不同大小的数组?
  • 这两种情况都是指针的大小?
  • 如果您至少需要知道向量正在使用多少内存,请使用sizeof(n.next) + n.next.capacity() * sizeof(Node*); 如果您需要确切知道向量已分配多少内存,请为向量提供您自己的分配器。

标签: c++


【解决方案1】:

作为标准的向量实现通常经过优化,以开始其生命周期超过必要的空间量。简单来说,即使您要求更少,实现也会为向量计划空间 - 例如 - 8 个对象,并且只有在超过此数量后才开始分配更多内存。

如果您从不使用这些元素,这会浪费一些内存,但会消除为添加的每个元素重新分配内存的性能开销。确切的数量取决于实现,有些人可能不会那样做,但这是一种典型的优化。

如果你想测量一个元素占用的空间,你需要更大的数量;例如,放入 100 个对象并检查,然后放入 200 个并检查。对于少量,您将看到一个恒定的大小,直到您达到阈值。

【讨论】:

  • 归根结底,我想知道在内存资源方面什么更有效:具有指针向量的结构,尽管并非结构的每个实例都恰好有 5向量中的指针;或拥有一个包含 5 个元素的固定长度数组的结构,例如 Node* next[5]。
  • 固定的 5 个数组在纯内存字节计数中效率更高。总是。但是,除非您拥有数百万个向量,否则使用向量的开销很小且可以忽略不计,并且您需要处理向量附带的东西所需的额外代码将消耗这些节省。此外,使用数组,向量可以避免更多错误的机会。所以,简而言之,vector 可能有 20% 的内存开销,但它仍然是更好的选择,除非你需要大量的它们。
【解决方案2】:

给定类型的所有对象大小相同,sizeof(n.next) 等价于sizeof(vector&lt;Node*&gt;)

vector 实例不包含元素,它只指向它们,因此实例本身的大小始终相同。

它的工作原理完全一样:

class A
{
public:
    A(int n) : p(new char[n]), s(n) {}
    int size() const { return s; }
private:
    char* p;
    int s;
};

int main()
{
    A a(1);
    A b(100);
    // These all print the same thing:
    std::cout << sizeof(a);
    std::cout << sizeof(b);
    std::cout << sizeof(A);
    // These are different:
    std::cout << a.size();  // Prints 1
    std::cout << b.size();  // Prints 100
}

如果你想知道你的向量总共占用了多少空间,你需要自己计算。

【讨论】:

    【解决方案3】:

    你想要n.next.size()

    sizeof 完全是一个编译时操作,因为它只是查看类型以确定存储它的一个实例需要多少字节。 sizeof(n.next) 告诉您保存 n.next 需要多少字节。由于它是vector,因此很可能使用 3 个指针(每个 8 个字节)来实现——一个指向分配数组的开头,一个指向数据的末尾,一个指向分配数组的末尾.

    【讨论】:

    • 不,我想知道我的下一个在满时会占用多少字节,这意味着当它有五个指向 Node 的指针时。但我不明白如何计算它。
    • @alekscooper 如果您确实需要如此密切地跟踪内存使用情况,那么您使用的是错误的编程语言。如果您只想知道发生了什么,请参阅stackoverflow.com/questions/910172/track-c-memory-allocations
    【解决方案4】:

    Vector 是具有固定“足迹”的动态结构,通常包含指向动态分配数据的指针。

    n.next.size() 返回动态分配数据的大小。 sizeof(n.next) 返回固定占用空间的大小。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-01
      相关资源
      最近更新 更多