dereferencing a pointer when passing by reference

C++PointersReference

C++ Problem Overview


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?

C++ Solutions


Solution 1 - C++

Dereferencing the pointer doesn't create a copy; it creates an lvalue that refers to the pointer's target. This can be bound to the lvalue reference 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.

Solution 2 - C++

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.

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) = 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 location of 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.

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.

*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.

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.

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

Solution 3 - C++

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.

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?

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMWrightView Question on Stackoverflow
Solution 1 - C++Mike SeymourView Answer on Stackoverflow
Solution 2 - C++WugView Answer on Stackoverflow
Solution 3 - C++Kerrek SBView Answer on Stackoverflow