What does `*&` in a function declaration mean? - c++

I wrote a function along the lines of this:
void myFunc(myStruct *&out) {
out = new myStruct;
out->field1 = 1;
out->field2 = 2;
}
Now in a calling function, I might write something like this:
myStruct *data;
myFunc(data);
which will fill all the fields in data. If I omit the '&' in the declaration, this will not work. (Or rather, it will work only locally in the function but won't change anything in the caller)
Could someone explain to me what this '*&' actually does? It looks weird and I just can't make much sense of it.

The & symbol in a C++ variable declaration means it's a reference.
It happens to be a reference to a pointer, which explains the semantics you're seeing; the called function can change the pointer in the calling context, since it has a reference to it.
So, to reiterate, the "operative symbol" here is not *&, that combination in itself doesn't mean a whole lot. The * is part of the type myStruct *, i.e. "pointer to myStruct", and the & makes it a reference, so you'd read it as "out is a reference to a pointer to myStruct".
The original programmer could have helped, in my opinion, by writing it as:
void myFunc(myStruct * &out)
or even (not my personal style, but of course still valid):
void myFunc(myStruct* &out)
Of course, there are many other opinions about style. :)

In C and C++, & means call by reference; you allow the function to change the variable.
In this case your variable is a pointer to myStruct type. In this case the function allocates a new memory block and assigns this to your pointer 'data'.
In the past (say K&R) this had to be done by passing a pointer, in this case a pointer-to-pointer or **. The reference operator allows for more readable code, and stronger type checking.

It may be worthwhile to explain why it's not &*, but the other way around. The reason is, the declarations are built recursively, and so a reference to a pointer builds up like
& out // reference to ...
* (& out) // reference to pointer
The parentheses are dropped since they are redundant, but they may help you see the pattern. (To see why they are redundant, imagine how the thing looks in expressions, and you will notice that first the address is taken, and then dereferenced - that's the order we want and that the parentheses won't change). If you change the order, you would get
* out // pointer to ...
& (* out) // pointer to reference
Pointer to reference isn't legal. That's why the order is *&, which means "reference to pointer".

This looks like you are re-implementing a constructor!
Why not just create the appropriate constructor?
Note in C++ a struct is just like a class (it can have a constructor).
struct myStruct
{
myStruct()
:field1(1)
,field2(2)
{}
};
myStruct* data1 = new myStruct;
// or Preferably use a smart pointer
std::auto_ptr<myStruct> data2(new myStruct);
// or a normal object
myStruct data3;

In C++ it's a reference to a pointer, sort of equivalent to a pointer to pointer in C, so the argument of the function is assignable.

Like others have said, the & means you're taking a reference to the actual variable into the function as opposed to a copy of it. This means any modifications made to the variable in the function affect the original variable. This can get especially confusing when you're passing a pointer, which is already a reference to something else. In the case that your function signature looked like this
void myFunc(myStruct *out);
What would happen is that your function would be passed a copy of the pointer to work with. That means the pointer would point at the same thing, but would be a different variable. Here, any modifications made to *out (ie what out points at) would be permanent, but changes made to out (the pointer itself) would only apply inside of myFunc. With the signature like this
void myFunc(myStruct *&out);
You're declaring that the function will take a reference to the original pointer. Now any changes made to the pointer variable out will affect the original pointer that was passed in.
That being said, the line
out = new myStruct;
is modifying the pointer variable out and not *out. Whatever out used to point at is still alive and well, but now a new instance of myStruct has been created on the heap, and out has been modified to point at it.

As with most data types in C++, you can read it right-to-left and it'll make sense.
myStruct *&out
out is a reference (&) to a pointer (*) to a myStruct object. It must be a reference because you want to change what out points at (in this case, a new myStruct).

MyClass *&MyObject
Here MyObject is reference to a pointer of MyClass. So calling myFunction(MyClass *&MyObject) is call by reference, we can change MyObject which is reference to a pointer. But If we do myFunction( MyClass *MyObject) we can't change MyObject because it is call by value, It will just copy address into a temporary variable so we can change value where MyObject is Pointing but not of MyObject.
so in this case writer is first assigning a new value to out thats why call by reference is necessary.

Related

Storing a reference within class

I'm trying to keep a reference to a pointer of a different class in my class. I'm trying to see if there is a way to do this without having to define it in the ctor. I cannot make a copy, as I'm using that specific pointer returned to do other things.
class MyClass {
private:
OtherClassPtr &m_ptr_ref;
public:
MyClass();
public:
void MyFunction() {
m_ptr_ref = otherClassPtr->GetPtrRef();
if(!m_ptr_ref)
return;
}
};
A reference needs to be initialized at the point of declaration, and cannot change to refer to a different object during its lifetime. Thus you need to set it in the constructor.
An alternative is to store a pointer. I think of a reference as a pointer with nicer syntax, though the different syntax gives it a different semantic meaning; it acts like the object that it refers to, and so has the same value and the same address as that object. Most relevant to your question, the assignment operator works like assignment to the object, rather than a pointer. This is the reason it cannot change referent.
You can keep a pointer to the pointer:
OtherClassPtr* m_ptr_ref;
/* ... */
m_ptr_ref = &otherClassPtr->GetPtrRef();
An alternative is to use std::reference_wrapper, but that is nothing more than a fancy pointer, and I don't see the advantage over using a pointer.

Everything in c++ by default is passed by value

In C++, are all types passed by value unless it comes with a & or * symbol?
For example in Java, passing an array as a function argument would be by default passing by reference. Does C++ give you more control over this?
EDIT: Thanks for all your responses, I think I understand the whole pass-by-value thing more clearly. For anyone who is still confused about how Java passes by value (a copy of the object reference), this answer really cleared it up for me.
In C++, are all types passed by value unless it comes with a & or *
symbol?
No if you pass something as * parameter (a pointer thereof) it is still passed by value. A copy of the pointer being passed is made. But both the original and copy point to the same memory. It is similar concept in C# - I believe also in Java, just you don't use * there.
That is why if you make changes to the outer objects using this pointer (e.g. using dereferencing), changes will be visible in original object too.
But if you just say assign a new value to the pointer, nothing will happen to the outer object. e.g.
void foo(int* ptr)
{
// ...
// Below, nothing happens to original object to which ptr was
// pointing, before function call, just ptr - the copy of original pointer -
// now points to a different object
ptr = &someObj;
// ...
}
For example in Java, passing an array as a function argument would be
by default passing by reference. Does C++ give you more control over
this?
In C++ or C if you pass array (e.g. int arr[]), what is being passed is treated as pointer to the first element of the array. Hence, what I said above holds true in this case too.
About & you are correct. You can even apply & to pointers (e.g., int *&), in which case now, the pointer indeed gets passed by reference - there is no copy made.
Probably tangential to your question, but I often take another direction to understand what happens when you call a function in C++.
The difference between
void foo(Bar bar); // [1]
void foo(Bar& bar); // [2]
void foo(Bar* bar); // [3]
is that the body in [1] will receive a copy of the original bar (we call this by value, but I prefer to think of it as my own copy).
The body of [2] will be working with the exact same bar object; no copies. Whether we can modify that bar object depends on whether the argument was Bar& bar (as illustrated) or const Bar& bar. Notice that in a well-formed program,[2] will always receive an object (no null references; let's leave dangling references aside).
The body of [3] will receive a copy of the pointer to the original bar. Whether or not I can modify the pointer and/or the object being pointed depends on whether the argument was const Bar* bar, const Bar* const bar, Bar* const bar, or Bar* bar (yes, really). The pointer may or may not be null.
The reason why I make this mental distinction is because a copy of the object may or may not have reference semantics. For example: a copy of an instance of this class:
struct Foo {
std::shared_ptr<FooImpl> m_pimpl;
};
would, by default, have the same "contents" as the original one (a new shared pointer pointing to the same FooImpl pointer). This, of course, depends on how did the programmer design the class.
For that reason I prefer to think of [1] as "takes a copy of bar", and if I need to know whether such copy will be what I want and what I need I go and study the class directly to understand what does that class in particular means by copy.

meaning of reference and pointer together?

In my project, there is a definition of a function call like this.
int32 Map(void * &pMemoryPointer)
In the calling place, the paramenter passed is void*, why cant we just receive it as a pointer itself, instead of this?
Without knowing what the Map function does, I'd guess that it sets the pointer. Therefore it has to be passed by reference.
Using a reference to a pointer, you can allocate memory and assign it to the pointer inside the function. For example
void DoSomething(int*& pointerReference)
{
// Do some stuff...
pointerReference = new int[someSize];
// Do some other stuff...
}
The other way to make functions like that is to return the pointer, but as the Map function in the question returns something else that can't be used.
Reading it backwards, this means that pMemoryPointer is a reference (&) to a pointer (*) to void. This means that whatever pointer you pass gets referenced, and any modification that the function will do to pMemoryPointer will also affect the original (passed) pointer (e.g. changing the value of pMemoryPointer will also change the value of the original pointer).
why cant we just receive it as a pointer itself, instead of this?
That's because by doing that, you are copying the pointer and any change that you'll make to the copy doesn't reflect to the original one.
void im_supposed_to_modify_a_pointer(void* ptr) { // Oh no!
ptr = 0xBADF00D;
}
int* my_ptr = 0xD0GF00D;
im_supposed_to_modify_a_pointer(my_ptr);
ASSERT(my_ptr == 0xBADF00D) // FAIL!
That's a weird function prototype IMHO, but it means
(Update) that the Map function accepts a reference to a void pointer as a parameter.
So I think, it is equivalent to declaring the function like this:
int32 Map(void** pMemoryPointer)

Inside the copy constructor of shared_ptr

I have some confusion about the shared_ptr copy constructor. Please consider the following 2 lines:
It is a "constant" reference to a shared_ptr object, that is passed to the copy constructor so that another shared_ptr object is initialized.
The copy constructor is supposed to also increment a member data - "reference counter" - which is also shared among all shared_ptr objects, due to the fact that it is a reference/pointer to some integer telling each shared_ptr object how many of them are still alive.
But, if the copy constructor attempts to increment the reference counting member data, does it not "hit" the const-ness of the shared_ptr passed by reference? Or, does the copy constructor internally use the const_cast operator to temporarily remove the const-ness of the argument?
The phenomenon you're experiencing is not special to the shared pointer. Here's a typical primeval example:
struct Foo
{
int * p;
Foo() : p(new int(1)) { }
};
void f(Foo const & x) // <-- const...?!?
{
*x.p = 12; // ...but this is fine!
}
It is true that x.p has type int * const inside f, but it is not an int const * const! In other words, you cannot change x.p, but you can change *x.p.
This is essentially what's going on in the shared pointer copy constructor (where *p takes the role of the reference counter).
Although the other answers are correct, it may not be immediately apparent how they apply. What we have is something like this:
template <class T>
struct shared_ptr_internal {
T *data;
size_t refs;
};
template <class T>
class shared_ptr {
shared_ptr_internal<T> *ptr;
public:
shared_ptr(shared_ptr const &p) {
ptr = p->ptr;
++(ptr->refs);
}
// ...
};
The important point here is that the shared_ptr just contains a pointer to the structure that contains the reference count. The fact that the shared_ptr itself is const doesn't affect the object it points at (what I've called shared_ptr_internal). As such, even when/if the shared_ptr itself is const, manipulating the reference count isn't a problem (and doesn't require a const_cast or mutable either).
I should probably add that in reality, you'd probably structure the code a bit differently than this -- in particular, you'd normally put more (all?) of the code to manipulate the reference count into the shared_ptr_internal (or whatever you decide to call it) itself, instead of messing with those in the parent shared_ptr class.
You'll also typically support weak_ptrs. To do this, you have a second reference count for the number of weak_ptrs that point to the same shared_ptr_internal object. You destroy the final pointee object when the shared_ptr reference count goes to 0, but only destroy the shared_ptr_internal object when both the shared_ptr and weak_ptr reference counts go to 0.
It uses an internal pointer which doesn't inherit the contests of the argument, like:
(*const_ref.member)++;
Is valid.
the pointer is constant, but not the value pointed to.
Wow, what an eye opener this has all been! Thanks to everyone that I have been able to pin down the source of confusion to the fact that I always assumed the following ("a" contains the address of "b") were all equivalent.
int const *a = &b; // option1
const int *a = &b; // option2
int * const a = &b; // option3
But I was wrong! Only the first two options are equivalent. The third is totally different.
With option1 or option2, "a" can point to anything it wants but cannot change the contents of what it points to.
With option3, once decided what "a" points to, it cannot point to anything else. But it is free to change the contents of what it is pointing to. So, it makes sense that shared_ptr uses option3.

Passing a class object pointer to a function for initialization C++

Lets say I have a class "A" and this function:
void initializationFunction(A* classPointer)
{
...
...
classPointer = new A(.....);
}
I write:
A* classPointer;
Then I pass this pointer to this function:
initializationFunction(classPointer);
This will not work unless I pass it by reference in the function declaration:
void initializationFunction(A*& classPointer);
I thought reference passing was for non-pointer type variables. I mean you don't need to pass an array by reference...
Thanks for the explanations :)
Yeah, that is true. You've to pass the argument by reference (or you can pass A** instead).
But the best solution is to write the constructor of A in such way that you wouldn't need this function in the first place. That is, whatever you're doing in this function, you should be doing that in the constructor itself.
If, however, you cannot edit the class, then you can do this instead:
A *initializationFunction()
{
A *obj = new A(.....);
//...
return obj;
}
A *classPointer = initializationFunction();
In my opinion, this approach is better than yours.
Note I didn't change the name of the function and other variables. I guess that isn't the point of the post. But I believe you would want better names for real code.
Either you declaration with the reference or the following one will do:
void initializationFunction(A** classPointer);
The point is that you are passing in a pointer argument and that you want to modify the value it had in the caller. This is an out parameter and out parameters should be passed by reference, not by value (reference here means either through a pointer or reference). This out parameter is a pointer, so you should pass a pointer to that pointer or a reference to that pointer.
In other words, you need to access the original argument in the caller stack to be able modify it. In the declaration
void initializationFunction(A* classPointer);
classPointer is akin to a local variable defined inside of initializationFunction and is just a copy of the classPointer you allocated in the caller function. Modifying a copy of classPointer will not modify the original variable, so you need a pointer to the original variable to be able to modify it. The same holds true if you use a reference to the original classPointer.
An alternative approach you have is returning the new classPointer from your function:
A* initializationFunction(void);
in this case the caller would simply do:
A* classPointer = initializationFunction();
You can pass any variable by reference. The difference between passing by reference and passing by value, is that when you pass by reference, you are in fact passing the very same pointer that is pointing to the value in that memory location, and when you pass by value you are just passing another reference to that memory location, and therefore anything you assign to it will NOT change the value of the parameter passed.
Either use a double pointer (a**) or a reference as you did.
In your first example, the pointer is passed by value (ie. the function gets a copy of the pointer). The object that the pointer points to is of course the same both in the calling code and inside the function.
In the second example, the pointer is passed by reference (ie. the function basically uses the same pointer as the calling code).
say you had a windows shortcut pointing to a text file in "My Documents".
you can copy that shortcut and paste it anywhere in windows, double click on it, and it opens the text file in "My Documents". That is passing by reference / pointer. The shortcut points to "where", then you use it to change the "stuff".
However, the code you posted doesn't "open" the file pointed to by the shortcut. It actually changes the shortcut to point to (actually create ) a new "file". But since the shortcut itself was first copied ( passed by value ), the effect is that you allocated memory but cannot access it. So analogously you changed the shortcut, created a "file", but then deleted the directory with that shortcut in there ( but your file is then lost in outer space !).
Unfortunately, there is really no analogy for passing a shortcut itself by reference, you would basically have to copy the shortcut back out of the directory, then replace the original text file in "my documents" with a shortcut to this new "file". Hope this helps instead of confuses it further :(.
The reason you have to pass the pointer by reference is that you're actually changing where in memory it points to. If you had already assigned it to an object and wanted to modify that object, passing it directly to the function would be fine.
When you do a Aptr = new A(...), you are
- Creating an 'A' object somewhere on the heap
- Assigning the address of the newly created object to Aptr
If the function doesn't have a reference to Aptr, the function can't change its value.
You can pass pointers by reference because pointers are also variables with their own address.
For example, in a 32-bit architecture, you can declare an unsigned int and use it as a pointer.
This is normal.
I explain:
void foo(X* toto)
{
toto=new X();
}
toto value will be poped out from call stack with it's initial value (as any other argument , pointer or not)
since it's not possible to change function argument value UNLESS it's a reference.
so:
void foo(X*& toto)
{
toto=new X();
}
Here you explicitely say toto argument as being X*& (X* for type , and & (reference) to let it's value be modified inside function foo)
Pointer types are the same than any other types. replace X* by int and you'll immediately find that toto won't be changed outside of function call unless passed as reference.
An X** would also have done the trick , using such implementation:
void foo(X** toto)
{
*toto=new X();
}
It should be:
void initializationFunction(A** classPointer)
{
...
...
*classPointer = new A(.....);
}
Call:
initializationFunction(&ptr);
the function will set the argument passed in to the new A(......);
example: http://ideone.com/u7z6W