c++ 当 unique_ptr 的别名超出范围时会发生什么?

c++ What happens when alias to unique_ptr goes out of scope?

如果我有一个唯一的指针并且我在一个函数中为它创建了一个别名,而这个别名超出了范围,为什么原来的 unique_ptr 没有被销毁?毕竟下面函数中定义的'b'和'x'在内存中基本是同一个对象。幕后发生了什么?

#include <iostream>
#include <memory>

void testfunc(std::unique_ptr<int>& x) {
  std::unique_ptr<int>& b = x;
}
int main() {
  std::unique_ptr<int> a(new int(5));
  std::cout << *a << std::endl; // 5
  testfunc(a);
  std::cout << *a << std::endl; // 5
}
#include <iostream>
#include <memory>

void testfunc(std::unique_ptr<int>& x) {  // you take a reference to a unique_ptr
  std::unique_ptr<int>& b = x;            // which will do nothing to the lifetime of
}                                         // the unique_ptr you pass to the function,
                                          // then you assign the passed parameter
                                          // to another reference. again, that does
                                          // nothing to the lifetime of the original.
int main() {
  std::unique_ptr<int> a(new int(5));
  std::cout << *a << std::endl; // 5
  testfunc(a);
  std::cout << *a << std::endl; // 5
}

After all, 'b' as defined in the function below is basically the same object in memory as 'x'.

完全没有。 x 是参考。引用不是对象,不会为它调用构造函数或析构函数。变量没有 "aliases"。有 for 类型,也称为 typedefs。

考虑用指针代替相同的代码:

void testfunc(std::unique_ptr<int>* x) {
  std::unique_ptr<int>* b = x;
}
int main() {
  std::unique_ptr<int> a(new int(5));
  std::cout << *a << std::endl; // 5
  testfunc(&a);
  std::cout << *a << std::endl; // 5
}

引用唯一会影响对象生命周期的情况是当引用绑定到临时对象时,但即便如此,它也会延长而不是缩短生命周期:

struct A {};

int main() {
    {
        A(); // Constructed and destructed
    }

    {
        A const& a = A(); // Constructed
        // Other instructions
    } // Destructed
}

Demo

A reference 可以被认为是元素的别名,因此它 references 另一个变量通过占用它的 value 并像它一样工作 ,但它不会被销毁,直到被析构函数调用或被程序员强行销毁 ,这也会销毁它引用的变量... 因为引用 只是一个可编辑的别名 ... 但是它们的寿命不同,因为 非引用 类型可以被移动,它变得超出范围...

"What is going on behind the scenes?"

在内存中,引用允许我们更改元素的值,如果经常使用而不是指针,这在 C... 但是,它的值不能被移动除非通过...一个引用的值不会改变除非使用赋值操作 直接间接 来自函数参数 x 本身就是一个 别名 ...

喜欢:x = std::make_unique<int>(6); 会将 a 的值改为 6... 但是您在这里所做的是...

auto& b = x;

除了 xreferences to a)所引用的值是 copied 并传递给 b(这就像 另一个别名 )...所以它类似于做:auto& b = a;,但由于 a超出范围,它引用 a 的值 间接 ...

#include <iostream>
#include <memory>

void testfunc(std::unique_ptr<int>& x)
{
    auto& b(x); // 'b' is an alias of 'x' and 'x' is an alias of 'a'
    b = std::make_unique<int>(6); // Setting 'b' to 6 meaning setting 'a' to 6...
    /* Now you can't do 'x = b' since you cannot assign a value to an alias and it is
       like a 'circular assignment operation'...*/
}
int main()
{
    std::unique_ptr<int> a(new int(5));
    std::cout << *a << std::endl; // 5 : Nothing happens, just initialization...
    testfunc(a);                  // It does not affect the reference...
    std::cout << *a << std::endl; /* 6 : Since reference is an 'alias', you
                                     changed 'a' as well...*/
} // It is freed after use by the destructor...

因此,人们的一般建议是,如果您不确定它的作用,应该避免引用(它可以 改变 真实变量 如果您不知道它的后果)...并花一些时间 learn about them...

如果你销毁 original 但是...,所有 references 本身都会失效...在这种情况下,当试图访问 destroyed (nullified) 对象的值时 undefined 导致 undefined behavior ...

您使用的是引用,C++ 中的引用与它所引用的类型不同。您可以通过引用与对象交互,但引用本身和被引用的对象具有不同的生命周期。当一个被销毁时,另一个不会自动被销毁。这意味着您可以将引用传递给函数,然后在函数结束时,当引用被销毁时,原始对象仍然有效。这允许在不需要复制甚至移动大型复杂对象的情况下传递它们。这是一个实现细节,但编译器通常只使用指针 "behind the scenes" 作为引用。

附带说明一下,C++ 中引用的这一方面导致了臭名昭著的悬挂引用问题。如果您持有对某个对象的引用并且该对象被销毁,那么您拥有的引用现在在技术上是无效的,并且如果您使用它,您将调用未定义的行为。不幸的是,语言中没有内置任何东西来自动检测或处理这种情况。您必须构建您的程序来避免它。