std::vector 记忆题

std::vector memory questions

所以我有一个项目让用户输入一个选项 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;

                  }
    }

这就是向量函数示例:

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;
}

所以问题是:

What is the memory cost of the statement vector vf, Considering I am not reserving memory for it if it is not needed.

(我假设你指的是 flov vf; 语句)。作为一般准则,内存使用量大致为 sizeof(the_vector) + sizeof(element_type) * the_vector.capacity()。可能会有更多特定于实现的调试信息,如果您的实现太愚蠢而无法在增加容量时四舍五入到内存分配页面大小....

请注意,std::vector 保证了连续的内存,因此大量意外的特定于实现的内存浪费的可能性大大低于说 std::map,其中内存碎片化并且每个单独的节点都可能受到影响分配开销、调试信息等。

What happens with the variable v once the function vectorx ends? Does returning v and calling it vi create a copy of v in memory?

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

因此,您不应在 vivfvd 中保留内存,然后再将返回的向量分配给它们...您可能最终会分配和释放完全没有使用的额外容量。

Is this overall memory efficient?

对于 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";
}
  • 对于内存成本,您需要按照 DumbCoder 的建议对其进行分析,它是系统特定的。

  • 变量 v 是过程的局部变量,因此它将在过程结束时被释放。 return 通常会创建一个副本,除非您的编译器进行了一些优化。研究 "Return Value Optimisation",这是特定于编译器的。

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

What is the memory cost of the statement vector vf;, considering I am not reserving memory for it if it is not needed.

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

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

What happens with the variable v once the function vectorx ends? Does returning v and calling it vi create a copy of v in memory?

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

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

Is this overall memory efficient?

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

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

What is the memory cost of the statement vector vf , Considering I am not reserving memory for it if it is not needed.

标准没有指定容器的初始容量应该是多少,因此您依赖于实现(参见 Initial capacity of vector in C++

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

What happens with the variable v once the function vectorx ends? Does returning v and calling it vi create a copy of v in memory?

这取决于编译器。最新的编译器将应用 Return Value Optimization or use the move constructor (see How to "return an object" in C++? and C++ vector, return vs. parameter).

Is this overall memory efficient?

我觉得可以改进

  1. 你用 reserve 太多了
  2. 您可以使用变体类型简化您的代码(例如,参见 boost variant)。