当作为参考给出时,std::unique_ptr 是否在作用域后自动清理?

Dav*_*óth 2 c++ reference smart-pointers

可以使用函数的指针返回,这在很多方面都很有用,但是否建议从该返回值中获取引用?

#include <iostream>
#include <memory>

using namespace std;

unique_ptr<int> give_a_number(){
    return std::make_unique<int>(6);
}

int main(){
   int& ret = *give_a_number();
   return ret;
}

Run Code Online (Sandbox Code Playgroud)

根据消毒剂,没有发生泄漏:

user@comp: Scrapbook$ g++ main.cpp -fsanitize=address -g
user@comp: Scrapbook$ 
Run Code Online (Sandbox Code Playgroud)

所以参考以某种方式被清理,但我不明白为什么。清理是如何发生的,甚至 unque_ptr 如何能够跟踪数据。这应该被视为安全行为吗?这是社区中公认的用法吗?

wal*_*nut 10

这里没有泄漏。一般由拥有的对象std::unique_ptr永远不会泄露,只要.release()不叫上所属std::unique_ptr

但是,您的程序确实有未定义的行为,因为生命周期不正确。如果您存储指向拥有对象的引用或指针,您将承担一些责任以确保正确的对象生命周期。

give_a_number()返回,按值,std::unique_ptr拥有该int对象。这std::unique_ptr因此被物化为语句中的临时对象

int& ret = *give_a_number();
Run Code Online (Sandbox Code Playgroud)

您不会将此临时移动到任何持久std::unique_ptr实例中。所以当临时对象在语句结束时被销毁时,int它拥有的对象也被销毁。现在你的参考是悬而未决的。

然后在 中使用悬空引用return ret;,导致未定义的行为。

您可以存储对所拥有对象的引用,但如果这样做,您必须确保std::unique_ptr拥有该引用的实例比该引用的生命int周期更长,以避免生命周期问题。例如以下是好的:

int main(){
   return *give_a_number(); // `std::unique_ptr` temporary outlives return value initialization
}
Run Code Online (Sandbox Code Playgroud)
int main(){
   auto ptr = give_a_number(); // `ptr` lives until `main` returns
   int& ret = *ptr;
   return ret;
}
Run Code Online (Sandbox Code Playgroud)

通常,将智能指针存储在上述自动变量中并*ptr在需要时通过取消引用来获取对象更安全。std::unique_ptr如果它没有被移出,那么它拥有的和 对象会一直存在到块的末尾。

但是,例如通过*ptr引用传递给函数是完全正确的。由于ptr超过了这样的函数调用,所以不会有任何问题。

如果您*give_a_number()直接将参数作为参数传递给函数,这也有效,因为std::unique_ptr临时函数也将比这样的调用存活得更久。但在这种情况下,std::unique_ptr它拥有的和 对象将只存在到语句结束(完整表达式),而不是块结束。