利用向量元素存储在堆中的事实?

时间:2014-07-07 01:36:51

标签: c++ pointers vector

让我们说你有类似的东西

#include <iostream>
#include <vector>


using namespace std;

vector<int> test()
{
    vector <int> x(1000);
    for (int i = 0; i < 1000; i++)
    {
        x[i] = 12345;
    }
    return x;
}

int main(int argc, const char * argv[])
{
    vector<int> a = test();
    return 0;
}

在一个函数中,你创建一个向量并用一些元素填充它(在这种情况下,我选择了12345,但他们不一定都是相同的。)

我已经读过,向量的元素存储在堆上,而引用和头数据存储在堆栈中。在上面的代码中,当返回x时,必须调用一个拷贝构造函数,这需要花费O(n)时间将所有元素复制到一个新的向量中。

但是,是否有可能利用堆上已存在的所有元素以便只返回类似于指向这些元素的指针的事实,然后创建一个使用该指针的向量以指向那些完全相同的元素 - 从而避免复制矢量的所有元素的需要?

1 个答案:

答案 0 :(得分:8)

编译器为您完成此任务,让您可以编写简单易读的代码,而不是为了优化而修改代码。

当您返回函数的值时,允许编译器 elide 返回值对象。实际效果是编译器只能在x的实际内存位置创建a

即使它没有这样做(例如它选择不出于某种原因,或者你通过编译器开关禁用它),那么仍然有可能移动

当移动发生时,向量只会将指针的所有权从x转移到返回值,然后从返回值转移到a。这会将x等留作空矢量,然后将其正确销毁。

您可以通过编写一个测试类(而不是vector<int>)来探索这个问题,该测试类为其默认构造函数,复制构造函数和移动构造函数打印出一些东西,例如。

#include <iostream>

struct A
{
    A() { std::cout << "default\n"; }
    A(A const &) { std::cout << "copy\n"; }
    A(A &&) { std::cout << "move\n"; }
};

A func() { A a; return a; }

int main()
{
    A b (func());
}

使用g ++输出:

default

使用g ++ -fno-elide-constructors输出:

default
move
move