C++ 按引用传递时取消引用指针
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11347111/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
dereferencing a pointer when passing by reference
提问by MWright
what happens when you dereference a pointer when passing by reference to a function?
当通过引用传递给函数时取消引用指针会发生什么?
Here is a simple example
这是一个简单的例子
int& returnSame( int &example ) { return example; }
int main()
{
int inum = 3;
int *pinum = & inum;
std::cout << "inum: " << returnSame(*pinum) << std::endl;
return 0;
}
Is there a temporary object produced?
是否产生了临时对象?
采纳答案by Mike Seymour
Dereferencing the pointer doesn't create a copy; it creates an lvaluethat refers to the pointer's target. This can be bound to the lvaluereference argument, and so the function receives a reference to the object that the pointer points to, and returns a reference to the same. This behaviour is well-defined, and no temporary object is involved.
取消引用指针不会创建副本;它创建一个引用指针目标的左值。这可以绑定到左值引用参数,因此函数接收对指针指向的对象的引用,并返回对相同对象的引用。这种行为是明确定义的,不涉及临时对象。
If it took the argument by value, then that would create a local copy, and returning a reference to that would be bad, giving undefined behaviour if it were accessed.
如果它按值获取参数,那么这将创建一个本地副本,并返回对它的引用将是不好的,如果访问它会给出未定义的行为。
回答by Wug
The Answer To Your Question As Written
您所写问题的答案
No, this behavior is defined. No constructors are called when pointer types are dereferenced or reference types used, unless explicitly specified by the programmer, as with the following snippet, in which the new
operator calls the default constructor for the int
type.
不,此行为已定义。当指针类型被取消引用或使用引用类型时,不会调用构造函数,除非程序员明确指定,如以下代码段,其中new
运算符调用int
类型的默认构造函数。
int* variable = new int;
As for what is really happening, as written, returnSame(*pinum)
is the same variable as inum
. If you feel like verifying this yourself, you could use the following snippet:
至于实际发生的事情,如所写,returnSame(*pinum)
与inum
. 如果您想自己验证这一点,可以使用以下代码段:
returnSame(*pinum) = 10;
std::cout << "inum: " << inum << std::endl;
Further Analysis
进一步分析
I'll start by correcting your provided code, which it doesn't look like you tried to compile before posting it. After edits, the one remaining error is on the first line:
我将首先更正您提供的代码,它看起来不像您在发布之前尝试编译。编辑后,剩下的一个错误在第一行:
int& returnSame( int &example ) { return example; } // semi instead of colon
Pointers and References
指针和引用
Pointers and references are treated in the same way by the compiler, they differ in their use, not so much their implementation. Pointer types and reference types store, as their value, the locationof something else. Pointer dereferencing (using the *
or ->
operators) instructs the compiler to produce code to follow the pointer and perform the operation on the location it refers to rather than the value itself. No new data is allocated when you dereference a pointer (no constructors are called).
编译器以相同的方式处理指针和引用,它们的用途不同,而不是它们的实现。指针类型和引用类型存储其他东西的位置作为它们的值。指针取消引用(使用*
或->
运算符)指示编译器生成代码以跟随指针并在它引用的位置而不是值本身上执行操作。取消引用指针时不会分配新数据(不调用构造函数)。
Using references works in much the same way, except the compiler automatically assumes that you want the value at the location rather than the location itself. As a matter of fact, it is impossible to refer to the location specified by a reference in the same way pointers allow you to: once assigned, a reference cannot be reseated (changed) (that is, without relying on undefined behavior), however you can still get its value by using the &
operator on it. It's even possible to have a NULL reference, though handling of these is especially tricky and I don't recommend using them.
使用引用的工作方式大致相同,除了编译器自动假定您需要该位置的值而不是该位置本身。事实上,不可能以指针允许的相同方式引用引用指定的位置:一旦分配,引用就不能重新设置(更改)(即,不依赖于未定义的行为),但是您仍然可以通过&
在其上使用运算符来获取其值。甚至可能有一个 NULL 引用,尽管处理这些特别棘手,我不建议使用它们。
Snippet analysis
片段分析
int *pinum = & inum;
Creates a pointer pointing to an existing variable, inum. The value of the pointer is the memory address that inum is stored in. Creating and using pointers will NOT call a constructor for a pointed-to object implicitly, EVER. This task is left to the programmer.
创建一个指向现有变量 inum 的指针。指针的值是存储 inum 的内存地址。创建和使用指针永远不会隐式调用指向对象的构造函数。这个任务留给了程序员。
*pinum
Dereferencing a pointer effectively produces a regular variable. This variable may conceptually occupy the same space that another named variable uses, or it may not. in this case, *pinum
and inum
are the same variable. When I say "produces", it's important to note than no constructors are called. This is why you MUST initialize pointers before using them: Pointer dereferencing will NEVER allocate storage.
取消引用一个指针有效地产生一个常规变量。这个变量在概念上可能会占用另一个命名变量使用的相同空间,也可能不会。在这种情况下,*pinum
和inum
是相同的变量。当我说“生产”时,重要的是要注意没有调用任何构造函数。这就是为什么你必须在使用它们之前初始化指针:指针解引用永远不会分配存储。
returnSame(*pinum)
This function takes a reference and returns the same reference. It's helpful to realize that this function could be written with pointers as well, and behave exactly the same way. References do not perform any initialization either, in that they do not call constructors. However, it is illegal to have an uninitialized reference, so running into uninitialized memory through them is not as common a mistake as with pointers. Your function could be rewritten to use pointers in the following way:
此函数接受一个引用并返回相同的引用。意识到这个函数也可以用指针编写并且行为完全相同是有帮助的。引用也不执行任何初始化,因为它们不调用构造函数。但是,使用未初始化的引用是非法的,因此通过它们进入未初始化的内存并不像使用指针那样常见。您的函数可以通过以下方式重写为使用指针:
int* returnSamePointer( int *example ) { return example; }
In this case, you would not need to dereference the pointer before passing it, but you would need to dereference the function's return value before printing it:
在这种情况下,您不需要在传递指针之前取消引用它,但是您需要在打印之前取消引用函数的返回值:
std::cout << "inum: " << *(returnSamePointer(pinum)) << std::endl;
NULL References
空引用
Declaring a NULL reference is dangerous, since attempting to use it will automatically attempt to dereference it, which will cause a segmentation fault. You can, however, safely check if a reference is a null reference. Again, I highly recommend not using these ever.
声明 NULL 引用是危险的,因为尝试使用它会自动尝试取消引用它,这将导致分段错误。但是,您可以安全地检查引用是否为空引用。再次,我强烈建议永远不要使用这些。
int& nullRef = *((int *) NULL); // creates a reference to nothing
bool isRefNull = (&nullRef == NULL); // true
Summary
概括
- Pointer and Reference types are two different ways to accomplish the same thing
- Most of the gotchas that apply to one apply to the other
- Neither pointers nor references will call constructors or destructors for referenced values implicitly under any circumstances
- Declaring a reference to a dereferenced pointer is perfectly legal, as long as the pointer is initialized properly
- 指针和引用类型是完成同一件事的两种不同方式
- 大多数适用于一个的陷阱也适用于另一个
- 在任何情况下,指针和引用都不会为引用的值隐式调用构造函数或析构函数
- 声明对解除引用的指针的引用是完全合法的,只要指针被正确初始化
回答by Kerrek SB
A compiler doesn't "call" anything. It just generates code. Dereferencing a pointer would at the most basic level correspond to some sort of load instruction, but in the present code the compiler can easily optimize this away and just print the value directly, or perhaps shortcut directly to loading inum
.
编译器不会“调用”任何东西。它只是生成代码。取消引用指针在最基本的层面上对应于某种加载指令,但在目前的代码中,编译器可以轻松地优化它并直接打印值,或者直接打印到加载的快捷方式inum
。
Concerning your "temporary object": Dereferencing a pointer always gives an lvalue.
关于您的“临时对象”:取消引用指针总是会给出一个左值。
Perhaps there's a more interesting question hidden in your question, though: How does the compiler implement passing function arguments as references?
不过,也许您的问题中隐藏了一个更有趣的问题:编译器如何实现将函数参数作为引用传递?