当通过引用函数传递时取消引用指针会发生什么?
这是一个简单的例子
int& returnSame( int &example ) { return example; }
int main()
{
int inum = 3;
int *pinum = & inum;
std::cout << "inum: " << returnSame(*pinum) << std::endl;
return 0;
}
是否有临时对象?
答案 0 :(得分:35)
取消引用指针不会创建副本;它会创建一个引用指针目标的左值。这可以绑定到 lvalue 引用参数,因此该函数接收对指针指向的对象的引用,并返回对该引用的引用。此行为是明确定义的,不涉及临时对象。
如果按值获取参数,则会创建一个本地副本,并返回对该参数的引用,如果访问它则会产生未定义的行为。
答案 1 :(得分:27)
对您的问题的答案
不,此行为已定义。除非程序员明确指定,否则在取消引用指针类型或使用引用类型时不会调用构造函数,就像下面的代码片段一样,new
运算符调用int
类型的默认构造函数。 / p>
int* variable = new int;
至于实际发生的事情,正如所写,returnSame(*pinum)
与inum
是同一个变量。如果您想亲自验证,可以使用以下代码段:
returnSame(*pinum) = 10;
std::cout << "inum: " << inum << std::endl;
进一步分析
我将首先更正您提供的代码,它在发布之前看起来并不像您尝试编译的那样。编辑后,剩下的一个错误出现在第一行:
int& returnSame( int &example ) { return example; } // semi instead of colon
指针和参考
编译器以相同的方式处理指针和引用,它们的使用不同,而不是它们的实现。指针类型和引用类型存储其他内容的 location 作为其值。指针解除引用(使用*
或->
运算符)指示编译器生成代码以跟随指针并对其引用的位置执行操作,而不是值本身。取消引用指针时不会分配新数据(不调用构造函数)。
使用引用的工作方式大致相同,只是编译器会自动假定您希望该位置的值而不是位置本身。事实上,不可能以指针允许的相同方式引用引用指定的位置:一旦分配,引用就不能重新定位(更改)(即,不依赖于未定义的行为),但是您仍然可以使用&
运算符来获取其值。甚至可以使用NULL引用,但处理这些引用特别棘手,我不建议使用它们。
摘录分析
int *pinum = & inum;
创建指向现有变量inum的指针。指针的值是存储inum的内存地址。创建和使用指针不会隐式调用指向对象的构造函数,EVER。这项任务留给程序员。
*pinum
取消引用指针会有效地生成常规变量。此变量在概念上可能占用与另一个命名变量使用的相同空间,或者可能不占用。在这种情况下,*pinum
和inum
是同一个变量。当我说“产生”时,重要的是要注意,而不是调用构造函数。这就是为什么你必须在使用它们之前初始化指针:指针解除引用永远不会分配存储。
returnSame(*pinum)
此函数接受引用并返回相同的引用。有用的是要意识到这个函数也可以用指针编写,并且行为方式完全相同。引用也不执行任何初始化,因为它们不调用构造函数。但是,使用未初始化的引用是非法的,因此通过它们运行未初始化的内存并不像指针那样常见。可以通过以下方式重写您的函数以使用指针:
int* returnSamePointer( int *example ) { return example; }
在这种情况下,您无需在传递指针之前取消引用指针,但在打印之前需要取消引用该函数的返回值:
std::cout << "inum: " << *(returnSamePointer(pinum)) << std::endl;
NULL引用
声明NULL引用很危险,因为尝试使用它会自动尝试取消引用它,这将导致分段错误。但是,您可以安全地检查引用是否为空引用。同样,我强烈建议不要使用这些。
int& nullRef = *((int *) NULL); // creates a reference to nothing
bool isRefNull = (&nullRef == NULL); // true
<强>摘要强>
答案 2 :(得分:1)
编译器不会“调用”任何东西。它只是生成代码。在最基本的级别取消引用指针将对应于某种加载指令,但在当前代码中,编译器可以轻松地优化它并直接打印该值,或者可以直接快捷地加载inum
。
关于你的“临时对象”:取消引用指针总是给出一个左值。
也许你的问题中隐藏着一个更有趣的问题,但是:编译器如何实现将函数参数作为引用传递?