函数通过 std::move返回的 unique_ptr 何时超出范围

问题描述

我正在处理一个存储在共享内存区域中并由 getter 返回的大对象。由于对象的大小,我遇到了按值返回对象导致堆栈溢出的问题。为了避免这种情况,我决定将 unique_ptr 返回到堆上对象的副本,我希望调用函数能够将其用作局部变量。请参阅下面的示例代码

注意:我正在处理的代码库是 C++11,而不是 C++14,所以我不能使用 std::make_unique

#include <memory>
struct AbsoluteUnit {
    char bigChungus[10000000];
    int bigChungusSize;
};
AbsoluteUnit g_absUnit;

std::unique_ptr<AbsoluteUnit> getAbsoluteUnit() {
    return std::move(std::unique_ptr<AbsoluteUnit>(new AbsoluteUnit(g_absUnit)));
}

void Example1()
{
    std::unique_ptr<AbsoluteUnit> absUnitPtr = getAbsoluteUnit();
    AbsoluteUnit& absUnit = *absUnitPtr.get();
    ///
    /// Some other code
    ///
}

void Example2()
{
    AbsoluteUnit& absUnit = *getAbsoluteUnit().get();
    ///
    /// Some other code
    ///
}

我的问题是:在 Example2 中,unique_ptr 何时超出范围?

在 Example1 中,我将 unique_ptr 存储在局部变量中,因此我希望它在函数退出时超出范围。但是在 Example2 中,我没有为其创建局部变量,那么在该行执行后 unique_ptr 会发生什么?它仍然在函数范围内,还是立即超出范围?

解决方法

get() 成员函数返回指向由 AbsoluteUnit 返回的 std::unique_ptr<AbsoluteUnit> 管理的 getAbsoluteUnit() 对象的指针。

然后将该托管 AbsoluteUnit 对象绑定到引用 absUnit

AbsoluteUnit& absUnit = *getAbsoluteUnit().get();

然而,std::unique_ptr 就在上述语句之后不复存在,因此托管 AbsoluteUnit 对象也不复存在。因此,absUnit 成为悬空引用


如果你想避免使用指针语法,你可以改写:

const std::unique_ptr<AbsoluteUnit> ptr = getAbsoluteUnit();
AbsoluteUnit& obj = *ptr;
// ... use obj instead of ptr

或者用 auto 更简洁:

const auto ptr = getAbsoluteUnit();
auto& obj = *ptr;
// ... use obj instead of ptr