Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么是c++;引用被认为比指针更安全? < > C++编译器生成一个非常类似的引用和指针的汇编代码,为什么使用指针比指针?_C++_Pointers_Reference - Fatal编程技术网

为什么是c++;引用被认为比指针更安全? < > C++编译器生成一个非常类似的引用和指针的汇编代码,为什么使用指针比指针?

为什么是c++;引用被认为比指针更安全? < > C++编译器生成一个非常类似的引用和指针的汇编代码,为什么使用指针比指针?,c++,pointers,reference,C++,Pointers,Reference,我确实看到了 讨论了它们之间的区别 编辑-1: 我在看g++为这个小程序生成的汇编代码: int main(int argc, char* argv[]) { int a; int &ra = a; int *pa = &a; } 因为引用(只是其他变量的别名)根据定义不能为NULL,提供了固有的安全层。引用总是从现有对象初始化的,因此它永远不能为NULL,而指针变量允许为NULL 编辑:感谢所有回复。是的,引用确实可以指向垃圾,我忘记了挂起引用。这有点安全,但

我确实看到了

  • 讨论了它们之间的区别
编辑-1:

我在看g++为这个小程序生成的汇编代码:

int main(int argc, char* argv[])
{
  int a;
  int &ra = a;
  int *pa = &a;
}

因为引用(只是其他变量的别名)根据定义不能为
NULL
,提供了固有的安全层。

引用总是从现有对象初始化的,因此它永远不能为NULL,而指针变量允许为NULL


编辑:感谢所有回复。是的,引用确实可以指向垃圾,我忘记了挂起引用。

这有点安全,但不是一回事。请注意,“悬挂引用”与“悬挂指针”的问题相同。例如,从作用域对象返回引用会产生未定义的行为,与指针完全相同:

int& f() { int x = 2; return x; }
唯一的好处是您不能创建空引用。即使你很努力:

int& null_ref = *((int*)0); // Dereferencing a null pointer is undefined in C++
                            // The variable null_ref has an undefined state.
作为类成员,指针是首选的,因为它们具有更好的赋值语义:初始化引用后不能重新赋值。如果类中有引用成员,编译器将无法提供默认赋值运算符

因此,C++不能去掉指针,可以自由地使用它们:将参数作为指针传递而不是作为(非const)引用,在调用站点中明确表示对象将被修改。这可以增加一点安全性,因为您可以用肉眼看到哪些功能可以修改对象


我有点像魔鬼代言人,但引用很容易被滥用。

好吧,你指出的答案就是答案。从“更安全”的角度来看,我认为基本上很难编写如下代码:

int* i;
// ...
cout << *i << endl; // segfault
但正如你提到的问题所说,这不仅仅是因为引用更安全


my2c

因为引用必须始终初始化,而且它们必须引用现有的对象,所以使用悬空引用要比使用未初始化/悬空指针困难得多(但决不是不可能)。此外,操作引用更容易,因为您不必担心获取地址和取消引用它们

<>但是,为了让你知道一个引用本身并不能使程序100%安全,考虑一下:

int *p = NULL;
int &r = *p;
r = 10; /* bad things will happen here */
或者这个:

int &foo() {
  int i;
  return i;
}

...

int &r = foo();
r = 10; /* again, bad things will happen here */
这取决于你如何定义“更安全”

编译器不允许您创建未初始化的引用或指向null的引用,也不允许您在使用它时意外地使引用引用引用到其他地方。这些更严格的规则还意味着您的编译器可以对常见错误给出更多的警告,而对于指针,它永远无法确定您是否真的想做您所做的事情


另一方面,语法的透明性——也就是Alexandre C.提到的在调用站点将参数作为引用进行传递的情况——使得我们很容易意识不到传递的是引用。因此,您可能没有意识到您应该维护参数的所有权和生存期,或者您的参数可能会被永久修改。

指针是一个自变量,可以重新分配指向另一个日期项、未初始化的内存,或者根本没有位置(NULL)。指针可以从同一类型的另一个指针中递增、递减、减法等。引用与现有变量关联,只是变量名的别名。

它被认为更安全,因为很多人“听说”它更安全,然后告诉其他人,他们现在也“听说”它更安全


没有一个理解引用的人会告诉你它们比指针更安全,它们也有同样的缺陷和失效的可能性

e、 g

#包括
内部主(空)
{
std::向量v;
v、 调整大小(1);
int&r=v[0];
r=5;//好,引用有效
v、 调整大小(1000);
r=6;//动臂!;
返回0;
}
编辑:由于对于引用是对象的别名还是绑定到内存位置似乎存在一些混淆,下面是标准(草案3225,章节
[basic.life]
)中的一段,该段明确指出引用绑定到存储,并且可以比创建引用时存在的对象更长寿:

如果,在对象的生命周期结束后,在对象占用的存储被重新使用之前,或者 释放后,将在原始对象占用的存储位置创建一个新对象,即
指向原始对象、引用原始对象的引用或原始对象的名称 对象将自动引用新对象,并且在新对象的生存期开始后,可以 用于操纵新对象,如果:

  • 新对象的存储正好覆盖原始对象占用的存储位置, 及
  • 新对象与原始对象的类型相同(忽略顶级cv限定符),并且
  • 原始对象的类型不是常量,如果是类类型,则不包含任何非静态 类型为常量或参考类型的数据成员,以及
  • 原始对象是
    T
    类型的最派生对象,而新对象是
    T
    类型的最派生对象(即,它们不是基类子对象)

假设语言中没有引用运算符
&
。然后,每当您想将对象的引用传递给函数时,都必须执行以下操作
int &foo() {
  int i;
  return i;
}

...

int &r = foo();
r = 10; /* again, bad things will happen here */
#include <vector>

int main(void)
{
    std::vector<int> v;
    v.resize(1);

    int& r = v[0];
    r = 5; // ok, reference is valid

    v.resize(1000);
    r = 6; // BOOM!;

    return 0;
}