为什么我不需要检查引用是否无效/ null?

jbu*_*jbu 36 c++ null reference

阅读http://www.cprogramming.com/tutorial/references.html,它说:

通常,引用应始终有效,因为您必须始终初始化引用.这意味着除了一些奇怪的情况(见下文),您可以确定使用引用就像使用普通的旧非引用变量一样.您不需要检查以确保引用未指向NULL,并且您不会被未初始化的引用所困扰,您忘记为其分配内存.

我的问题是如何知道在初始化引用后对象的内存未被释放/删除.

它归结为我不能在信仰上接受这个建议,我需要一个更好的解释.

任何人都能解释一下吗?

Bri*_*ndy 72

您无法知道引用是否无效:

除了通过如何使用引用之外,无法知道您的引用是否引用了有效内存.例如,如果您不确定何时删除内存,则不希望对堆上创建的内容使用引用.

您也永远无法知道您使用的指针是否指向有效内存.

你可以使用指针和引用进行NULL检查,但通常你永远不会使用引用进行NULL检查,因为没有人会编写这样的代码:

int *p = 0;
int &r = *p;//no one does this
if(&r != 0)//and so no one does this kind of check
{
}
Run Code Online (Sandbox Code Playgroud)

何时使用参考?

您可能希望在以下情况下使用引用:

//I want the function fn to not make a copy of cat and to use
// the same memory of the object that was passed in
void fn(Cat &cat)
{
   //Do something with cat
}

//...main...
Cat c;
fn(c);
Run Code Online (Sandbox Code Playgroud)

引用自己的脚很难参考:

用引用来引导你自己的脚比用指针更难.

例如:

int *p;
if(true)
{
  int x;
  p = &x;
}

*p = 3;//runtime error
Run Code Online (Sandbox Code Playgroud)

你不能用引用做这种事情,因为引用必须用它的值初始化.并且您只能使用示波器中的值对其进行初始化.

你仍然可以通过参考射击自己的脚,但你必须真的尝试这样做.

例如:

int *p = new int;
*p = 3;
int &r = *p;
delete p;
r = 3;//runtime error
Run Code Online (Sandbox Code Playgroud)

  • "你可能不想在堆上创建的东西中使用引用"?为什么不?如果我在堆上创建一个实例,通过引用方法传递它然后释放它,我很好.唯一的问题是如果方法存储该引用并假设它将保持有效. (8认同)
  • @Brian:我会说,当您需要修改对象的方法时要使用引用,如果需要避免复制但又不想修改它,则要使用常量引用。只要对象的生命周期超过方法调用的生命周期,对象在内存中的分配位置就没有区别。所以,不,这并不罕见。 (2认同)
  • @Steven:我更专注于我的评论并使其更加明确:"例如,如果您不确定何时删除内存,则不希望对堆上创建的内容使用引用." (2认同)

Edw*_*nge 5

你不能.你也不能用指针.考虑:



struct X
{
  int * i;
  void foo() { *i++; }
};

int main()
{
  int *i = new int(5);
  X x = { i };
  delete i;
  x.foo();
}
Run Code Online (Sandbox Code Playgroud)

现在,你可以在X :: foo()中放入什么代码以确保i指针仍然有效?

答案是没有标准检查.在调试模式下有一些技巧可以在msvc上运行(检查0xfeeefeee或其他什么),但是没有任何东西能够始终如一地工作.

如果你需要某种对象来确保指针不指向释放的内存,你需要比引用或标准指针更聪明的东西.

这就是为什么在使用指针和引用时需要非常小心所有权语义和生命周期管理.

  • 您总是可以使用别名指针.假设`p`和`q`都是指向同一内存的指针.删除`p`并设置`p = NULL`.现在,`q`怎么样?它无效,也不是NULL.当你删除指针时,知道指针的所有别名是什么并不总是微不足道的. (5认同)

小智 5

在 C++ 中,引用主要用作函数的参数和返回类型。对于参数,由于函数调用的性质,引用不能引用不再存在的对象(假设是单线程程序)。在返回值的情况下,应该限制自己返回生命周期长于函数调用的类成员变量,或者传递给函数的引用参数。