引用c++时默认的析构器行为。

问题描述 投票:0回答:2

我在互联网上搜索了一下,但我找不到任何关于引用时默认析构器行为的资源。

举个例子,我在互联网上搜索了一下,但是找不到任何关于在引用上的默认破坏函数的行为的资源。

struct A{
   int &a;
   A(int&i): a(i){}
}
void f(){
    int* i = new int;
    A* a = new A(*i);
    delete a; // is i been destroyed?
}

在这两种情况下,我在哪里可以找到相关的资源?或者谁能给我解释一下它的行为?

c++ standards destructor
2个回答
2
投票

引用不是对象。它们没有析构器。它们是有寿命的。对象和C++中的其他类型一样,也有寿命。

不同的是,当一个对象的生命期结束时,它的析构器会被调用,但当其他类型的生命期结束时,它们的资源会被释放。

在引用的情况下,它们持有的资源是指向另一个值的内存地址。而不是值本身。所以当它被释放时,值会保持不变。被释放的是存储的内存地址,而不是值。

当你使用newdelete时,你是在手动说明一个生命周期何时开始(new时)和何时结束(delete时)。

在你的例子中,你的寿命X和Y,将是如下的。

struct A{
   int &a;
   A(int&i): a(i){}
}
void f(){
    int* i = new int; // ----------------------------------|X
    A* a = new A(i); // -------------------|Y              |X
    delete a; // is i been destroyed? // --|Y              |X
} //                                                       |X
//                                                         |X...

正如你所看到的,X的生命期永远持续下去, 因为你没有手动删除它,而是用new创建了它。这意味着,在 i在您删除了 a.

PD:你应该写 new A(*i) 来代替,否则你会得到一个编译器错误。


2
投票

如果你能修正代码,使它确实能编译,也许会变得更清楚。你不能将一个指针传递给一个想要引用的方法。你需要先去引用指针(在这个上下文中,这是一个相当误导的表达方式).所以你实际上是在传递一个普通变量。

对于一个接受引用的函数,你可以做的是传递一个本来就不是指针的变量。

如果你意识到这一点,那么就会变得更加清楚,destructor销毁被引用的值是没有意义的,它不能保证它是动态创建的,也不能保证它需要被销毁。delete 自动成为指针的成员。你需要明确地这样做)。)


1
投票

简而言之,它不会被销毁,你会得到一个内存泄漏。

现在的问题是你实际需要什么行为。可能有不同的对象所有权管理策略。最好的做法是使用智能指针而不是原始指针,至少对于所有权很重要的对象来说是这样。例如,你可以采用shared_ptr。

struct A{
   std::shared_ptr<int> a;
   A(std::shared_ptr<int> i): a(i){}
}
void f(){
    std::shared_ptr<int> i(new int);
    std::shared_ptr<A> a(new A(i));
}

这个例子开启了其他的问题:是否应该用智能指针的值来代替原始指针? i 在其他地方使用?它是否应该在物体上存活下来?a?

如果没有在其他地方使用,你可以(也应该)使用? unique_ptr 而不是。生命期管理的不同战略可能采用其他模式。


1
投票

销毁一个引用什么也不做--它并没有销毁被引用的对象。当你记得我们将引用传递给大多数方法时,这一点就变得很清楚了。方法不会销毁被引用的对象。 指针也是一样的。销毁一个指针并不会销毁它所指向的对象。

在你的例子中, int 所指 i 被泄露了。

© www.soinside.com 2019 - 2024. All rights reserved.