我在互联网上搜索了一下,但我找不到任何关于引用时默认析构器行为的资源。
举个例子,我在互联网上搜索了一下,但是找不到任何关于在引用上的默认破坏函数的行为的资源。
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++中的其他类型一样,也有寿命。
不同的是,当一个对象的生命期结束时,它的析构器会被调用,但当其他类型的生命期结束时,它们的资源会被释放。
在引用的情况下,它们持有的资源是指向另一个值的内存地址。而不是值本身。所以当它被释放时,值会保持不变。被释放的是存储的内存地址,而不是值。
当你使用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)
来代替,否则你会得到一个编译器错误。
如果你能修正代码,使它确实能编译,也许会变得更清楚。你不能将一个指针传递给一个想要引用的方法。你需要先去引用指针(在这个上下文中,这是一个相当误导的表达方式).所以你实际上是在传递一个普通变量。
对于一个接受引用的函数,你可以做的是传递一个本来就不是指针的变量。
如果你意识到这一点,那么就会变得更加清楚,destructor销毁被引用的值是没有意义的,它不能保证它是动态创建的,也不能保证它需要被销毁。delete
自动成为指针的成员。你需要明确地这样做)。)
简而言之,它不会被销毁,你会得到一个内存泄漏。
现在的问题是你实际需要什么行为。可能有不同的对象所有权管理策略。最好的做法是使用智能指针而不是原始指针,至少对于所有权很重要的对象来说是这样。例如,你可以采用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
而不是。生命期管理的不同战略可能采用其他模式。
销毁一个引用什么也不做--它并没有销毁被引用的对象。当你记得我们将引用传递给大多数方法时,这一点就变得很清楚了。方法不会销毁被引用的对象。 指针也是一样的。销毁一个指针并不会销毁它所指向的对象。
在你的例子中, int
所指 i
被泄露了。