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

在这两种情况下调用对象的析构函数在哪里?我知道这个问题的标准答案总是“当对象的范围结束时”

但是考虑通过引用传递的情况。在 mystruct 的主体内foo_ref 具有该函数的范围。那么对象的析构函数不会在函数结束时被调用foo_ref吗?

也许我的困惑与对事物范围的理解有关。请让我知道我的推理哪里出错了。

4

3 回答 3

3

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

const绑定到临时表达式的引用具有延长临时对象生命周期的特殊规则,但这不适用于您的代码。

您的困惑可能源于一个非常流行的常见问题解答中的声明,它类似于“引用是被引用的对象”。如您所见,这不是真的。引用与它所引用的对象是分开的,每个都有自己的生命周期(而且很少看到这样做正确,但是引用的生命周期延长比对象的生命周期更长也是合法的)

于 2012-09-07T23:17:53.010 回答
1

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

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

于 2012-09-07T23:18:30.093 回答
1

在示例代码中,析构函数 formystructmain.

指针当指针超出范围时,所指向的对象不会发生任何事情。如果指针不存在,对象的生命周期将保持不变。当然,还有一个重要的细节:由new/创建的对象在new[]它们被deleted/ delete[]d 之前一直存在,而由 / 分配的malloc内存在它被freed 之前一直存在。

引用引用只不过是现有对象的附加名称。除了const指向临时对象的引用之外,引用的生命周期对被引用对象的生命周期没有影响;当该对象正常超出范围时调用析构函数(对临时对象的const引用使临时对象保持活动状态,直到const引用超出范围)。

使用术语“对象”是一种简化,指针或引用确实指向内存;它不会以任何方式“跟踪”实际对象。例如,可以在指针超出范围之前销毁被指向的对象,或者在引用超出范围之前销毁被引用的对象。这些无效的指针/引用分别称为“悬空指针”和“悬空引用”:

int* i = new int(5);
int& j = *i;
delete i;

// i is now a dangling pointer, and j is now a dangling reference
于 2012-09-07T23:25:36.753 回答