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

C++ 利用向量元素存储在堆中的事实?,c++,pointers,vector,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,

假设你有这样的东西

#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;
}
#包括
#包括
使用名称空间std;
向量测试()
{
向量x(1000);
对于(int i=0;i<1000;i++)
{
x[i]=12345;
}
返回x;
}
int main(int argc,const char*argv[]
{
向量a=测试();
返回0;
}
在函数中创建一个向量并用一些元素填充它(在本例中,我选择了12345,但它们不一定都相同)

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


然而,是否有可能利用堆中已经存在的所有元素来返回指向这些元素的指针,然后创建一个使用该指针的向量来指向这些完全相同的元素,从而避免复制向量的所有元素

编译器会帮您完成这项工作,让您可以自由编写漂亮、易于阅读的代码,而不是为了优化而弄乱代码

当您为函数返回一个值时,允许编译器省略返回值对象。净效果是编译器只需在
a
的实际内存位置创建
x

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

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

您可以通过编写一个测试类(而不是
vector
)来探索这一点,该类为其默认构造函数、复制构造函数和移动构造函数打印出一些内容,例如

#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++-fno elide构造函数的输出:

default
move
move

移动语义和NRVO。这是一个好的开始。@CaptainObvlious,不,不要显式地这样做来移出返回值。@Xaqq,它已经为您移出了(如果NRVO没有发生),如果您随后将返回类型设为右值引用,您就开始进入了。@Xaqq,它会阻止(N)RVO。
default
move
move