考虑以下简单代码。
struct test
{
test(int n):numelements(n){ arr = new int[numelements] }
int numelements;
int* arr;
~test()
{
delete[] arr;
}
}
void foo_ref(test& x,n)
{
// set first n elements of the array x.arr to random numbers
}
void foo_ptr(test* x,n)
{
// set first n elements of the array x->arr to random numbers
}
int main(void)
{
test mystruct(1000000);
foo_ref(mystruct,20);
// foo_ptr(&mystruct,20);
return 0;
}
在上面的代码中,foo_ref
和foo_ptr
执行完全相同的操作
它所指的对象即。 mystruct
。但是foo_ref通过引用传递对象
和foo_ptr通过指针。
在两种情况下其中是被调用对象的析构函数?我知道这个问题的标准答案总是“当一个对象的范围结束时”
但请考虑通过引用传递的情况。在foo_ref
的正文中
mystruct具有该功能的范围。那么在函数foo_ref
的末尾不会调用对象的析构函数吗?
也许我的困惑与理解某事的范围有关。 请让我知道我在推理中的错误。
答案 0 :(得分:3)
我在这里没有看到任何const
引用,因此答案是“引用和指针之间的对象生存期没有区别”。
const
引用有一个特殊的规则,可以延长临时对象的生命周期,但这不适用于您的代码。
你的混淆可能源于a statement made in a very popular FAQ,它有点像“引用是引用的对象”。如你所见,这不是真的。引用与它引用的对象是分开的,每个引用都有自己的生命周期(并且很少看到这样做是正确的,但是在引用的生命周期中延伸的时间比对象的生命周期更长是合法的)
答案 1 :(得分:1)
foo_ref
将有一个参数,它是具有该函数范围的参数。无论是指针还是引用都不会对mystruct的删除产生任何影响。
如果按值传递结构,则副本将在函数末尾销毁。如果你做了一些愚蠢的事情,比如在副本中引用相同的arr那么你可能会在原始结构仍在使用时意外删除arr。在这种情况下,您可能希望使用共享指针来跟踪arr使用的内存,而不是手动删除它。
答案 2 :(得分:1)
在示例代码中,mystruct
的末尾会调用main
的析构函数。
指针当指针超出范围时,指向的对象没有任何反应。对象的生命周期保持指针永远不存在的状态。当然,有一个重要的细节:由new
/ new[]
创建的对象存在,直到它们为delete
d / delete[]
d,并且由malloc
分配的内存}存在直到free
d。
引用引用只不过是现有对象的附加名称。除了指向临时对象的const
引用之外,引用的生命周期对于被引用的对象的生命周期没有影响;当该对象通常超出范围时,将调用析构函数(const
对临时对象的引用会使临时值保持活动状态,直到const
引用超出范围)。
Using the term "object" is a simplification,指针或引用确实指向内存;它不以任何方式“跟踪”实际对象。例如,可以在指针超出范围之前销毁被指向的对象,或者在引用超出范围之前销毁被引用的对象。这些无效指针/引用分别称为“悬空指针”和“悬空引用”:
int* i = new int(5);
int& j = *i;
delete i;
// i is now a dangling pointer, and j is now a dangling reference