C#中的安全不在C ++中,指针/引用的简单返回

时间:2011-12-10 11:57:57

标签: c# c++ pointers reference dangling-pointer

C ++代码:

person* NewPerson(void)
{
  person p;
  /* ... */
  return &p; //return pointer to person.
}

C#代码:

person NewPerson()
{
  return new person(); //return reference to person.
}

如果我理解这一点,那么C ++中的示例就不行了,因为p会 超出范围,函数将返回一个野指针(悬空指针)。

C#中的示例没问题,因为只要有对它的引用,匿名新人就会留在范围内。 (调用函数得到一个。)

我做对了吗?

7 个答案:

答案 0 :(得分:4)

  

C ++中的示例不正常,因为'p'将超出范围,并且该函数将返回无效指针。

正确。

  

C#中的示例是可以的,因为只要有任何对它的引用,匿名“new Person”就会保留在范围内。

这或多或少是正确的,但你的术语并不完全正确。 C#中的范围可以使用非限定名称的文本区域。这里的对象没有名称。 生命周期运行时间段,在此期间保证存储位置有效。连接范围和生命周期;当控件离开与作用域关联的代码时,通常允许在该作用域内声明的本地生命周期结束。 (有些情况下,当地人的生命时间比控制在他们的范围内的时间更长或更短。)

另请注意,它不是对Person对象的任何引用,使其保持活动状态。引用必须是 rooted 。你可以有两个Person对象相互引用但是无法访问;每个人都有参考的事实并不能让他们活着;其中一个参考文献必须扎根。

答案 1 :(得分:2)

此示例中的作用域规则是类似的,但在C#中,如果返回的值被分配给某个东西,那么只要某个东西持有对它的引用,它就不会被垃圾收集。如果它没有分配给某个东西,那么什么都没有引用它,并且下次收集器执行时它将被垃圾收集

答案 2 :(得分:2)

person* NewPerson(void)
{
  person p();
  /* ... */
  return &p; //return pointer to person.
}

p不是person,请参阅most vexing parse。因此,您将收到编译器错误。

其余的,是的,你是对的。

答案 3 :(得分:1)

在C ++中,'p'将存在于堆栈中,因此在函数返回时会被破坏。在C#中,垃圾收集器知道在最后一个引用丢失之前不会破坏它。

('clobber'在这里松散地使用......:p)

答案 4 :(得分:1)

是的,你做得对。

然而,在C ++中,你真的会喜欢这个

person NewPerson()
{
  person p;
  /* ... */
  return p; //return person.
}

并且非常肯定在通话中

person x = NewPerson();

编译器将优化复制返回值。

答案 5 :(得分:0)

  

我做对了吗?

BTW:在C ++中的人p();声明一个函数,不会调用默认的ctor。只写人p;

答案 6 :(得分:0)

这在C ++中不起作用,因为您返回对临时的引用,一旦该函数结束就会被销毁。您需要在堆上创建一个new人,然后返回对该人的引用。