Your function expects a reference to an actual string pointer in the calling scope, not an anonymous string pointer. Thus:
Copystring s;
string* _s = &s;
myfunc(_s);
should compile just fine.
However, this is only useful if you intend to modify the pointer you pass to the function. If you intend to modify the string itself you should use a reference to the string as Sake suggested. With that in mind it should be more obvious why the compiler complains about you original code. In your code the pointer is created 'on the fly', modifying that pointer would have no consequence and that is not what is intended. The idea of a reference (vs. a pointer) is that a reference always points to an actual object.
Answer from Chris on Stack OverflowYour function expects a reference to an actual string pointer in the calling scope, not an anonymous string pointer. Thus:
Copystring s;
string* _s = &s;
myfunc(_s);
should compile just fine.
However, this is only useful if you intend to modify the pointer you pass to the function. If you intend to modify the string itself you should use a reference to the string as Sake suggested. With that in mind it should be more obvious why the compiler complains about you original code. In your code the pointer is created 'on the fly', modifying that pointer would have no consequence and that is not what is intended. The idea of a reference (vs. a pointer) is that a reference always points to an actual object.
The problem is that you're trying to bind a temporary to the reference, which C++ doesn't allow unless the reference is const.
So you can do one of either the following:
Copyvoid myfunc(string*& val)
{
// Do stuff to the string pointer
}
void myfunc2(string* const& val)
{
// Do stuff to the string pointer
}
int main()
// sometime later
{
// ...
string s;
string* ps = &s;
myfunc( ps); // OK because ps is not a temporary
myfunc2( &s); // OK because the parameter is a const&
// ...
return 0;
}
c++ - Difference between pointer to a reference and reference to a pointer - Stack Overflow
I am absolutely confused on the topic of references vs pointers
Can I take a reference of a pointer in C++? - Stack Overflow
c++ - What is a reference-to-pointer? - Stack Overflow
Videos
First, a reference to a pointer is like a reference to any other variable:
Copyvoid fun(int*& ref_to_ptr)
{
ref_to_ptr = 0; // set the "passed" pointer to 0
// if the pointer is not passed by ref,
// then only the copy(parameter) you received is set to 0,
// but the original pointer(outside the function) is not affected.
}
A pointer to reference is illegal in C++, because -unlike a pointer- a reference is just a concept that allows the programmer to make aliases of something else. A pointer is a place in memory that has the address of something else, but a reference is NOT.
Now the last point might not be crystal clear, if you insist on dealing with references as pointers. e.g.:
Copyint x;
int& rx = x; // from now on, rx is just like x.
// Unlike pointers, refs are not real objects in memory.
int* p = &x; // Ok
int* pr = ℞ // OK! but remember that rx is just x!
// i.e. rx is not something that exists alone, it has to refer to something else.
if( p == pr ) // true!
{ ... }
As you can see from the above code, when we use the reference, we are not dealing with something separated from what it refers to. So, the address of a reference is just the address of what it refers to. Thats why there is no such thing called the address of the reference in terms of what you are talking about.
Pointer to a pointer
A pointer in C++ is just a value which stores a memory location (generally as a 32-bit value).
Let's say you had a user input integer value (78 == 0x4E in hex).
It would be stored in memory in a similar way to this (I'm purposely simplifying things for this example):
CopyMemory address Value
0x12345678 0x0000004E
If you wanted to create a "pointer" to this value, it would look like this in memory:
CopyMemory address Value
0x22334455 0x12345678
At memory address 0x22334455 you now have a "pointer" whose value is 0x12345678, or the memory address of where the user input integer value (0x4E) is stored.
Let's say you wanted to create a "pointer" to this pointer value. It would look like this:
CopyMemory address Value
0x11335577 0x22334455
You now have a new "pointer" value in memory which is storing the memory address of the previously-defined pointer value.
Pointers can be created like this indefinitely - the key is remembering that a pointer is just another value that the compiler interprets as a memory location (and it provides various access semantics such as * and -> which are special to "pointer" types).
Reference to a pointer
A reference can be thought of as a view, or alias, on to another real object. When you create a reference to a pointer called myReference, you are simply defining a new name called myReference which can be used to access the pointer which you have previous defined in memory.
Internally, references are implemented using pointers, but this is beyond the scope of your question.
References have restrictions over other types in C++ - for example, you must always initialize a reference to "refer" to a real object when you create it, while a pointer may point to memory which is invalid, or uninitialised.
Pointer to a reference
This doesn't exist. As stated earlier, a reference is merely an alias to another object. You can't "point" to a reference, because it isn't an object in itself but merely another name for a real object.
Of course, you can have a pointer to the object that a reference is referring to. But now we are back in vanilla pointer territory.
Note about parameters
When you pass a parameter by value to a method or routine, you are essentially passing a "copy" of the object to the method. Any changes you make to the value within the routine will be lost when the routine returns, because the parameter will be treated as a local variable in the context of the routine.
If you want to modify a parameter which is passed in so the client (calling) code can access the change, you must pass the parameter by pointer or by reference.
For example:
Copyvoid myMethod(int myValue)
{
// NOTE: This change will be lost to the caller!
myValue = 5;
}
void myMethod2(int* myValue)
{
// Correct way of modifying pointer parameter value
*myValue = 5;
}
void myMethod3(int& myValue)
{
// Correct way of modifying reference parameter value
myValue = 5;
}
Let's now say that your method wants to allocate memory for a pointer. You could be tempted to do this:
Copyvoid myMethod4(int* myValue)
{
// Warning: You will lose the address of the allocated
// memory when you return!
myValue = new int[5];
}
But remember, you are modifying the copy of the pointer value here, not the real pointer value. Since you are wanting to modify the pointer in this routine, and not the value that the pointer "points" to, you need to pass it in as a "pointer to a pointer" or a "reference to a pointer":
Copyvoid myMethod5(int** myValue)
{
// Correct way of allocating memory in a method
// via pointer-to-pointer
*myValue = new int[5];
}
void myMethod6(int*& myValue)
{
// Correct way of allocating memory in a method
// via reference-to-pointer
myValue = new int[5];
}
In these bottom 2 examples, the code which is calling myMethod5 and myMethod6 will correctly get the memory address of the newly-allocated memory via the myValue parameter pointer or reference.
On one hand, there is the Brief Introduction To C++’s Model For Type- And Resource-Safety which is considered to be an authoritative source for the obvious reason that Bjarne Stroustrup himself co-authored it, and it says :
"A reference is a restricted form of a pointer with some added syntactic sugar, so our techniques for pointers also deal with references."
On the other hand, there is the C++ FAQ which is also considered to be an authoritative source, and it says this about references:
"Important note: Even though a reference is often implemented using an address in the underlying assembly language, please do not think of a reference as a funny looking pointer to an object. A reference is the object, just with another name. It is neither a pointer to the object, nor a copy of the object. It is the object. There is no C++ syntax that lets you operate on the reference itself separate from the object to which it refers."
To me, it appears that these statements contradict each other, or do they? I don't know anymore. Could someone enlighten me and for once and for all, define exactly what a reference is, and what's the difference between that and a pointer? Thanks.
I am not sure what your problem is, as the error code given does not match your code.
Your second example with int Foo(const Obj* &ptr) works exactly as intended, and compiles fine if you make DoSomethingconst.
To comment your three thoughts:
- If you const things correctly, the error goes away.
- I really, really dislike such out-paramteres. It is much cleaner to return a struct or a pair of int and pointer. That way the caller can write
const auto[ret, p] = Foo();and not have to explicitely declare the pointer that you may not want to use. - Passing pointers to pointers is C-style, due to lack of references, and just make the code harder to read, with no benefit.
Below is slightly modified code that compiles fine, with a better Foo too, as mentioned in my answer to 2.:
Copy#include <utility>
struct Obj
{
void DoSomething() const;
};
// This is ugly of course, used just to have a valid ptr to return
Obj global;
int Foo(const Obj* &ptr) {
// do something...
ptr = &global;
return 5;
}
std::pair<int, const Obj*> BetterFoo()
{
// do something...
return {5, &global};
}
int main() {
const Obj* p1 = nullptr;
int ret1 = Foo(p1);
const auto[ret2, p2] = BetterFoo();
p1->DoSomething();
p2->DoSomething();
}
One way to deal with this situation is to use typedef or using. For example, using ObjPtr = Obj*; now the function would be int Foo(const ObjPtr& ptr) { ... }.
The above will be able to modify not only the pointed object, but also the pointer in itself. As an example, consider the below code:
void func(int*& ptr) {
*ptr = 1;
ptr = 0;
}
int main() {
int x = 0;
int* y = &x;
func(y);
}
At the end of the execution, x has value 1 and y is 0 (as you can see).
Notice that for the sake of the example I've used 0 as a null pointer, but if you are using C++11 you should probably use nullptr instead (which does not have an overloaded operaror<< for std::ostream).
This concept can possibly be assimilated by taking a look at the following code:
template<class Type> using ptr = Type*;
ptr<int>& x;
or
std::unique_ptr<int>& x;
In these examples, x is a reference to a type (ptr<int> and then std::unique_ptr<int>), which just so happens to be a pointer/class with pointer semantic (operator* and operator->).
A possibly interesting digression can be made on the position of a const qualifier in the pointer. Consider these two instances:
void func(const int*& ptr)void func(int*const& ptr)
Their meanings are:
- pointer by reference to a constant int.
- pointer by constant reference to an int.
And following the above analogy with ptr they would be:
ptr<const int>&ptr<int> const&
Therefore the first will fail to execute *ptr = 1 in the body of the function (because the int is constant), but will happily execute ptr = 0.
The second will behave conversely, allowing *ptr = 1 (because the pointed int is not constant), while disallowing ptr = 0 (because the pointer is constant).
Of course, in the case of:
void func(const int*const& ptr)
which in the ptr analogy would be ptr<const int> const&, both of them wouldn't be allowed.
And when to use this? Is it advisable to do this?
Like every feature, you'll find its usefulness when you'll need it. But just as a general idea, some people used it to reset the pointer after freeing a dynamically allocated resource (I'm not recommending this, see below).
Let's take this example:
free_my_int(int*& ptr) {
delete ptr;
ptr = nullptr;
}
int* x = new int(42);
free_my_int(x);
At the end of the execution, x would be correctly freed and the pointer automatically set to nullptr (null pointer). This was done to prevent ugly segmentation faults or "pointer freed has not been allocated" error messages caused by a missing ptr = nullptr.
But with C++11 and C++14 there is very little use of pointers and even less of reference to pointers. Most of the things pointers where used for are not replaced with other standard construct (see std::optional, std::unique_ptr, std::shared_ptr or std::reference_wrapper for example).
Let's compare all three options:
void func(type* param); // 'param' is a 'type*' variablevoid func(type& param); // 'param' is a reference to a 'type' variablevoid func(type*& param); // 'param' is a reference to a 'type*' variable
void func(type* param)
{
type x;
...
param = &x;
// Argument 'param' is regarded as a local variable in this function,
// so setting 'param = ...' will have no effect outside this function
}
Of course, if you do *param = ..., then it will effect the contents of the memory pointed by param. And you can also do param[5] = ... for example, and effect other areas within that memory space.
void func(type& param)
{
type x;
...
param = x;
// Argument 'param' is regarded as a reference to a variable outside this
// function, so setting 'param = ...' will effect the referenced variable
}
Here, you will only change the referenced variable itself, so it's safer than declaring the function as void func(type* param), and then pass the address of type param by calling func(¶m).
void func(type*& param)
{
type x;
...
param = &x;
// Argument 'param' is regarded as a reference to a variable outside this
// function, so setting 'param = ...' will effect the referenced variable
}
This is similar to declaring the function as void func(type** param), and then pass the address of type* param by calling func(¶m), but again, it is safer for the same reason mentioned above.