2012-09-07 75 views
1

请考虑以下简单代码。通过引用传递对象而不通过指针传递的对象的作用域

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_reffoo_ptr上 执行完全相同的操作是指即该对象。 mystruct。但是,foo_ref通过引用 和foo_ptr通过指针传递对象。

在这两种情况下其中是被调用的对象的析构函数?我知道这个问题的标准答案始终是“当一个对象的范围结束”

但是考虑通过引用传递的情况。在foo_ref 的内部,mystruct具有该函数的范围。所以在功能foo_ref的末尾不会调用该对象的析构函数吗?

也许我的困惑与某物的范围的理解做。 请让我知道我在我的推理中犯错的地方。

+2

你知道':包含numElements(N),编曲(新INT [包含numElements])'是有效的,也只要'numelements'在你的类中的'arr'之前声明。 – chris

+1

让我们看看代码foo_ref – Mark

+0

@标记见编辑。他们只是函数,说初始化一些元素或任何 – smilingbuddha

回答

3

我没有看到任何const引用在这里,因此答案是“在引用和指针之间对象的生命没有什么不同”。

const引用势必临时表达式有延长临时对象寿命的特殊规则,但这并不适用于你的代码。

您的困惑可能源自于a statement made in a very popular FAQ,它沿着“参考是被引用的对象”的方向行事。正如你所看到的,这是不正确的。引用是从它引用的对象分开,每个人都有自己的生命周期(这是非常难得一见这个做得正确,但比对象的生存期延长较长它是参考的寿命甚至法律)

+0

谢谢!我的印象是,当引用超出范围时,引用的析构函数(因此对象本身)被调用,这将导致内存被释放。所以通过你的回答,我认为这种说法是错误的。 – smilingbuddha

+0

因此,当引用的析构函数被称为引擎盖下发生了什么?我认为与它所指的对象的析构函数完全没有关系? – smilingbuddha

+0

没有这样的东西作为参考的析构函数。 *对象*具有析构函数,而引用只是引用对象的一种方式。如果某个地方有某个对象的引用,那么该对象何时/如何被销毁就没有影响。也许你把引用与*引用计数*混淆了,这是一个非常不同的事情。 – Oktalist

1

foo_ref将有一个参数,并且它是具有该函数范围的参数。无论是指针还是引用,都不会对删除mystruct有任何影响。

在你的价值,则副本会在函数结束时被销毁传递结构的情况。如果你做了一些愚蠢的事情,比如引用副本中的相同arr,那么当原始结构仍在使用时,你可能会意外删除arr。在这种情况下,您可能想使用共享指针来跟踪arr使用的内存,而不是手动删除它。

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 
+0

引用实际上是内存位置的名称,而不是对象。我更彻底地解释了[这里](http://stackoverflow.com/a/4715888/103167)。 –

+0

@ BenVoigt谢谢。我已经添加了该链接的段落。而且,我承认我没有想过创建悬挂引用的方法。 –

+1

我甚至没有谈论悬挂引用。在与旧的对象相同的内存中创建新对象是合法的,只要类型匹配,现有引用可以与新对象正常工作。 –

相关问题