std ::矢量记忆问题

时间:2015-02-09 09:27:02

标签: c++ vector

所以我有一个项目让用户输入一个选项 op ,取决于它将使用的 vector 的类型,即vector<int> vector<float>vector<double>

为此,我创建了3个将根据 op 调用的函数,它的工作方式如下:

    #include <iostream>
    #include <vector>

    using namespace std;
    typedef vector<int> intv;
    typedef vector<float> flov;
    typedef vector<double> douv;
    intv vectori(int opt, int t);
    flov vectorf(int opt, int t);
    douv vectord(int opt, int t);

    int main(){
    int opt;
    size_t t;
    cout << "Size: \n";
    cin >> t;
    cout << "Option? \n";
    cin >> op;
    flov vf;
    douv vd;
    intv vi;
    switch (op){
            case 00:
                    vi.reserve(t);
                    vi=vectori(0,t);
                    break;
            case 01:
                    vf.reserve(t);
                    vf=vectorf(0,t);
                    break;
            case 02:
                    vd.reserve(t);
                    vd=vectord(0,t);
                    break;

                  }
    }

这将是示例vectori函数:

intv vectori(int op, int t)
{
intv v;
v.reserve(t);
// Do stuff
return v;
}

示例vectorf函数是类似的(因此是vectord):

flov vectorf(int op, int t)
{
flov v;
v.reserve(t);
// Do stuff
return v;
}

所以问题是:

  • 语句向量vf的内存开销是多少,考虑到如果不需要,我不会为它保留内存。
  • 一旦函数 vectorx 结束,变量 v 会发生什么?返回v并调用它vi会在内存中创建v的副本吗?
  • 整体记忆效率如何?

4 个答案:

答案 0 :(得分:1)

  

语句向量vf的内存开销是多少,考虑到如果不需要,我不会为它保留内存。

(我假设你的意思是flov vf;声明)。作为一般准则,内存使用量大致为sizeof(the_vector) + sizeof(element_type) * the_vector.capacity()。对于特定于实现的调试信息,可能会有更多内容,如果你的实现在增加容量的同时执行它太愚蠢,那么可以进行内存分配页面大小的调整....

请注意std::vector保证连续内存,因此大量意外实现特定浪费内存的可能性大大低于std::map,其中内存的碎片和每个单独的节点可能用于分配,调试信息等的开销。

  

一旦函数vectorx结束,变量v会发生什么?返回v并调用它vi会在内存中创建v的副本吗?

使用C ++ 11,您可以预期vi将直接填充数据vectorf()名义上返回(由于返回值优化),或者它将被移动构造,这意味着实际上vi将获得存储向量元素的指针到动态分配内存的所有权。它相对轻量级,并且随着处理元素数量的增加而变慢。

出于这个原因,你不应该在vivfvd之前保留记忆,然后再为它们分配返回的矢量...你最终可能会分配和释放额外的没有使用它的能力。

  

这整体记忆效率如何?

对于t的大值,使不必要的变量的开销变得微不足道,所以是的。请考虑上面提到的reserve问题 - 因为在分配期间您的瞬间内存使用可能会不必要地过度。


所有这一切,如果您最终选择了三种类型的数据之一供该程序在该运行期间使用,您可能最好使用这样的模板和结构:

#include <iostream>
#include <vector>

template <typename T>
void f(int t)
{
    std::vector<T> v(t);
    ... do all your work with v...
}

int main()
{
    int opt;
    size_t t;
    if (std::cout << "Size:\n" && 
        std::cin >> t &&
        std::cout << "Option? \n" &&
        std::cin >> op)
    {
        switch (op)
        {
          case 00: f<int>(t); break;
          case 01: f<float>(t); break;
          case 02: f<double>(t); break;
        }
    }
    else
        std::cerr << "unable to read inputs from stdin\n";
}

答案 1 :(得分:1)

  

语句向量vf的内存成本是多少,考虑到我   如果不需要,则不为它保留记忆。

标准没有指定容器的初始容量,因此您依赖于实施(请参阅Initial capacity of vector in C++

无论如何,许多实现都会将容量从零开始。

  

一旦函数vectorx结束,变量v会发生什么?是否   返回v并调用它vi在内存中创建v的副本?

这取决于编译器。最新的编译器将应用Return Value Optimization或使用移动构造函数(请参阅How to "return an object" in C++?C++ vector, return vs. parameter)。

  

这整体记忆效率如何?

我认为可以改进。

  1. 您过度使用reserve
  2. 您可以使用变体类型简化代码(例如,请参阅boost variant)。

答案 2 :(得分:0)

  • 对于内存成本,您需要将其描述为DumbCoder建议的,它是系统特定的。

  • 变量v是过程的本地变量,因此它将在结束时释放。除非编译器有一些优化,否则返回通常会创建一个副本。研究“返回值优化”,这是特定于编译器的。

  • 另一种更好的矢量传递方式是通过引用参数 void funct(std :: vector&amp; vec,...)

答案 3 :(得分:0)

  

语句vector vf;的内存开销是多少,考虑到如果不需要,我不会为它保留内存。

从技术上讲,这取决于标准库的实现。它预先分配一些内存(即以非零capacity()开头)是在其权利范围内。但我不认为任何实现实际上都是这样 - 如果向量被分配给(就像你正在做的那样)那将是非常浪费的。

如果你想100%确定,请检查标准库的vector::vector()实现,但我真的希望不涉及动态内存分配。

  

函数v结束后,变量vectorx会发生什么?返回v并将其调用vi会在内存中创建v的副本吗?

在C ++ 11及更高版本中,答案是,不会产生额外的副本。向量v 移动到向量vi(缓冲区所有权已转移)。

在C ++ 03中,可能会发生副本。如果编译器足够聪明,它可能会发现它可以直接在vi中构造返回的向量,但我担心这可能是一个太大的精神飞跃。当然,检查装配。

  

这整体记忆效率如何?

是的,不太可能涉及任何未使用的堆内存。并且vector对象本身可能只占用堆栈上的3个指针大小。

除此之外:DumbCoder在你的代码中指出了一个严重的缺陷 - reserve()vi和类似向量的调用。这些 nothing 可以提供帮助。向量取得v缓冲区的所有权(在C ++ 11中移动),或者它将知道要分配多少内存(v.size()),因此不会有不必要的重新分配。 reserve()只有在您期望多次添加到向量时才会有意义(例如,push_back()调用的循环),并且不希望在此期间发生不必要的重新分配。