是否可以 return 引用 std::vector 中的数据,并在向量超出范围后保留该引用?

Is it possible to return an a reference to the data in an std::vector, and preserve that reference after the vector goes out of scope?

我习惯用 C 语言编程,在那种语言中我只是 return 一个指向数据的指针,然后调用者负责释放数据,然而,从我所拥有的阅读,向量的析构函数将在它超出范围时立即调用,导致它的数据被取消分配。

一旦引用被 returned,内容的大小就不会改变,所以如果我能有一个指向数据的指针,然后我可以手动删除那将是理想的。我真正不想做的是将所有数据复制到一个新容器中,因为这个向量会变得非常大。

如有任何帮助,我们将不胜感激。到目前为止,我看到的每个解决方案都涉及按值复制并依靠编译器对其进行优化,或者使用额外的 类 来包装向量。

编辑:明确地说,我想保留的向量的唯一部分是指向其数据的指针(即您使用 vector.data() 方法获得的指针),我不需要保留有关原始向量的任何其他信息。

引用的全部意义在于它不拥有该对象。在这里使用 std::unique_ptr 是完全有效的,它拥有该对象并且可以返回给您的调用者。

你的函数定义如下(我假设是一个整数向量),C++14 或更高版本:

std::unique_ptr<std::vector<int>> getVector() {
    auto vec = std::make_unique<std::vector<int>>(/*any ctor args you want*/);
    // for example
    vec->push_back(1);
    vec->push_back(2);
    return vec;
}

调用者可以进行如下操作:

int main() {
    auto vec = getVector();
    std::cout << vec->size() << std::endl;
}

并且当 unique_ptr 超出范围时,矢量将被安全删除。请注意,如果您使用的是 C++11,则不会有 std::make_unique 并且需要执行以下操作:

std::unique_ptr<std::vector<int>> vec(new std::vector<int>(/* ctor args */));

像这样写你的代码:

std::vector<blah> my_function_that_returns_a_vector ()
{
    std::vector <blah> v;
    ... code to populate v ...
    return v;
}

NVRO 将删除副本。相反,返回的向量直接在调用者的堆栈帧中构造。

针对您描述的用例的良好(安全且快速)解决方案:不要 return 引用,而是 return 范围外的向量。

Is it possible to return an a reference to the data in an std::vector, and preserve that reference after the vector goes out of scope?

是的...如果您使用静态存储。具有静态存储持续时间的对象的生命周期一直延伸到程序结束。因此,当它们超出范围时,它们仍然存在。请注意,静态存储是全局状态,这通常是有问题的。尽可能避免并小心使用。

带自动存储:否


I would just return a pointer to the data, and then the caller would be responsible for freeing the data

这是一个有问题的方法。调用者如何知道他们负责释放数据?调用者如何知道如何释放数据?调用者如何知道他们何时可以释放数据(如果有其他数据用户)?这一切都取决于调用者阅读文档,理解它,而不是出错。这是许多内存泄漏、通过无效指针访问和双重释放崩溃的根源。

std::vector 通过将生命周期与容器对象相关联来解决这些问题(在某种程度上;C 或 C++ 中没有任何接口是不会被滥用的)。


If I could just have a pointer to the data that I could manually delete afterwards that would be ideal.

你不能这样。 std::vector总是破坏它的数据,并且不可能将数据窃取到向量外部(除非通过移动或交换进入另一个向量)。

向量超出范围后无法保留对向量的引用,因为正如您提到的那样,它将被删除。一旦向量被删除,存储在该地址的内存将不可访问。或者,您可以在范围外声明变量,在范围内编辑它。您通过引用提到 returning - 是否可以通过引用将向量传递给函数,而只是 return void?这样,您就可以在不同的范围内编辑同一个矢量。