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

时间:2018-11-10 08:02:38

标签: c++ smart-pointers

如果我有一个唯一的指针,并且在函数中为其创建了一个别名,而该别名超出了范围,为什么原始的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
}

4 个答案:

答案 0 :(得分:2)

您正在使用的是一个引用,而C ++中的引用是与引用不同的类型。您可以通过引用与对象进行交互,但是引用本身和被引用的对象具有不同的生存期。当一个被销毁时,另一个不会自动销毁。这意味着您可以将引用传递给函数,然后在函数结束时销毁该引用,原始对象仍然有效。这允许绕过大型复杂对象,而无需复制甚至移动它们。这是一个实现细节,但对于编译器来说,通常只是使用“幕后”指针作为引用。

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

答案 1 :(得分:0)

#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
}

答案 2 :(得分:0)

  

毕竟,下面函数中定义的“ b”与“ x”在内存中基本上是同一对象。

一点也不。 x是参考。引用不是对象,因此不会为其调用构造函数或析构函数。没有变量的“别名”。有用于类型的类型,也称为typedef。

用指针代替相同的代码:

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

答案 3 :(得分:0)

可以将reference视为元素的别名,因此它通过吸收其 value 并工作 just来引用就像它一样,但是它不会被销毁者调用或被程序员强行销毁,这也会销毁它引用的变量...,因为引用只是可编辑的别名 ...但是,它们的寿命有所不同,因为可以移动非引用类型,并且该类型变得超出范围 ...

  

幕后发生了什么?

在内存中,引用使我们可以更改元素的值,并且如果经常使用来代替指针,而指针通常是C 中的常见做法。 strong>但是,除非通过,否则它的值不能移动。除非使用分配操作直接进行更改,否则引用的值将不会更改< / em>或间接 ,即功能参数 x 本身就是别名。 ..

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

auto& b = x;

除了xa 的引用)所引用的值被复制并传递给{{1} }(它的作用类似于另一个别名)...因此,它类似于:b,但是由于auto& b = a;不在范围内,因此它引用了{{1} }的值间接 ...

a

因此,人们的普遍建议是,如果不确定其作用,则应避免引用(如果您不知道,可以更改 实际变量后果)...并花一些时间来learn about them ...

但是,如果您破坏了原始 ...,则所有引用本身都将失效...在这种情况下,当尝试访问< em>已销毁的已无效)对象是未定义,导致undefined behavior ...