利用vector的元素存储在堆中的事实

Exploiting fact that elements of vector are stored in heap?

本文关键字:事实 存储 vector 元素 利用      更新时间:2023-10-16

假设你有这样的内容

#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)时间将所有元素复制到一个新向量中。

然而,是否有可能利用堆上已经存在的所有元素的事实,只返回指向这些元素的指针之类的东西,然后只创建一个使用该指针指向这些完全相同的元素的向量,从而避免需要复制vector的所有元素?

编译器会为您完成这些工作,让您可以腾出时间编写漂亮、易于阅读的代码,而不是为了优化而乱写代码。

当你为函数返回一个值时,允许编译器省略返回值对象。最终结果是编译器可以在a的实际内存位置创建x

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

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

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

#include <iostream>
struct A
{
    A() { std::cout << "defaultn"; }
    A(A const &) { std::cout << "copyn"; }
    A(A &&) { std::cout << "moven"; }
};
A func() { A a; return a; }
int main()
{
    A b (func());
}

使用g++输出:

default

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

default
move
move