I recently saw a function that is being declared as:
void func(type* ¶m);
I already know the difference between type* param and type& param. How does the above differ from them? And when to use this? Is it advisable to do this?
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*' variable
void func(type& param); // 'param' is a reference to a 'type' variable
void 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.
Related
I am trying to create a function that allocates memory. It allocates it, but the problem is that it only appears to do so inside the function, but after it returns the memory allocated is no longer there. Almost as if I am allocating memory with another pointer, but there should be no other there.
template<class T> struct rmv_ptr { using type = T; };
template<class T> struct rmv_ptr<T*> { using type = T; };
template<class T> struct rmv_ptr<const T*> { using type = T; };
template<class T> bool alloc(T inst, int size)
{
return (nullptr != (inst = new typename rmv_ptr<T>::type[size]));
}
Say I call it like this:
wchar_t* a;
alloc(a, 10);
inst will be wchar_t*, so a's pointer should point to the allocate memory, no?
When you pass an integer to a function, you cannot change the integer.
When you pass a pointer to a function, you cannot change the pointer.
When you pass a pointer to a function, you can change the pointed-to value.
Pass-by-non-const-reference is the exception; it allows you to change the passed value. Passing a pointer by reference therefore allows you to change the pointer.
On an unrelated note, the base rule for "remove pointer" template logic won't work. The problem is that you have two uses of T. There's the argument T& inst, which has to match T* returned by new. I.e. if T is int, then rmv_ptr<int>::type is int, and new will return an int*. But you can't assign that int* to int& inst.
Pointers are no different from non-pointers as modifications are not visible outside when passed by value to a function:
void foo(int* p) { p = 0; } // only modifies the local p
void foo(int a) { a = 0; } // only modifies the local a
However, pointers allow you to modify what the pointer does point to and that can be observed by the caller:
// assume p points to an int
void bar(int* p) { *p = 42; }
This will not modify p itself. When called via
int x;
int xp = &x;
bar(xp);
then p inside bar is a copy of xp, though they both point to the same int.
But when you call new, then new returns you a pointer to the allocated memory, so you need to change the pointers value, not just the pointee. Either pass it by reference, or return the pointer from the function (making it a parameter is of no use anyhow).
I was reading some code online and I found them passing node*& instead of just node* and I didn't really understand why.
My understanding was that you pass parameters by reference when you either want your changes to sort of propagate back to the original variable outside of the function (which a pointer would do) or if you wanted to avoid copying the object every time the function is called to avoid the copying overhead which is also what a pointer would do.
Am I wrong or are they? If I am, what am I getting wrong?
When you pass by reference, it acts as an alias -- be it a normal object or a pointer.
To explain in detail, let's consider below declaration:
int i = 10, *pi = &i;
Now following are the different meanings of passing and using them in various functions:
void foo_pointer (int* p) // 1st (can pass `&i` and `pi`)
{
*p = 0; // modifies `i`
p = nullptr; // no effect on `pi`
}
void foo_pointer_reference (int*& p) // 2nd (can pass `pi`)
{
*p = 0; // modifies `i`
p = nullptr; // modifies `pi`
}
void foo_const_pointer_reference (const int*& p) // 3rd (can pass `pi`)
{
*p = 0; // ERROR
p = nullptr; // modifies `pi`
}
void foo_const_pointer_const_reference (const int* const& p) // 4th (can pass `&i` and `pi`)
{
*p = 0; // ERROR
p = nullptr; // ERROR
}
From above examples, you can see that another use case of declaring T*& as a function parameter is that, it restricts only pointer passing to that function. i.e. in above case &i is not allowed to be passed to 2nd and 3rd functions. However pi can be passed to all the functions.
You can pass a pointer by reference if you want the function you call to change the pointer to point to something else.
Other than that, I don't see any valid reason (but that is sometimes a valid reason).
In a recent assignment for a data structures class, we we're expected to use this "*&" in a function parameters list. I am having trouble finding info on why this exists, and even what it does. Is it standard practice to use this?
Here's a code snippet
template <class T>
Thing <T> * action(const T &dataIn, Thing <T> *& thingIn)
{
if(thingIn == NULL)
{
Node <T> *newThing = new Thing <T> (dataIn);
newThing->ptr = thingIn;
thingIn= newThing ;
return(newThing );
}
}
I guess another part of my question is, why use "*&" at all couldn't you just send the pointer?
It is used for a reference type pointing to a pointer
Example
int *&ref = ptr;
in the above example, ref is a reference to an int pointer ptr
which then can be passed in to a function
function(int *&ref)
fun(int x)
fun takes an int value
fun(int* x)
fun takes an int pointer by value
fun(int& x)
fun takes an int by reference
fun(int*& x)
fun takes an int pointer by reference - the value of the pointer to x as seen by the caller can be changed by fun
If you have a structure for example like
struct A
{
//...
};
then a function parameter can look like
void f( A * &pa );
In this declaration A * means pointer type and & means that this pointer is passed to the function by reference.
Compare these two code snippets
void f( A * &pa )
{
pa = new A();
}
//...
A *p = nullptr;
f( p );
After calling the function the variable p will have the address of the allocated memory in the function because it was passed to the function by reference.
If the function would be declared like this
void f( A * pa )
{
pa = new A();
}
//...
A *p = nullptr;
f( p );
then after calling the function the pointer p would not be changed because the function deals with a copy of the pointer.
let's look into this:
void fun( int i );
we pass parameter by value, it means function can use int i but cannot change variable that is used to pass that value:
void fun( int i ) { i = 123; }
int main()
{
int j = 0;
fun( j );
std::cout << j << std::endl; // j is still 0
}
on another side when we use refernce, variable would be changed:
void fun( int &i ) { i = 123; }
int main()
{
int j = 0;
fun( j );
std::cout << j << std::endl; // j is 123 now
}
if you understand this concept you should be able to undestand more complex types, just use typedef or more modern using:
typedef char * pchar;
fun( pchar &p );
fun( char *&p ); // this is the same as before
you can actually use it in program or at least in your mind, that should simplify your understanding that a pointer is the same variable as anything else. It also helps to understand other complex types like pointer to pointer etc.
In a recent assignment for a data structures class, we we're expected to use this "*&" in a function parameters list. I am having trouble finding info on why this exists, and even what it
does.
C++ declarations can be read from right to left. It's a reference to a pointer.
Is it standard practice to use this?
Not really. See below.
I guess another part of my question is, why use "*&" at all couldn't you just send the pointer?
A reference allows you to modify the object which is being referenced.
A pointer is an object. So a reference to a pointer allows you to modify a pointer. Modifying a pointer means to make it point somewhere else. So if you take a *& in a function, then it means that the function can change where the pointer outside of the function points to.
Changing the destination of a raw pointer is not something you do very often in C++, but as always, it depends on your application domain.
Changing the destination of an existing pointer certainly feels more like C-style programming, and there are no references in C. In C, you would use ** instead of *& to accomplish this, and pass a pointer to a pointer, accordingly.
I would pass T*& pointer, when I am intending to change the pointed value inside the function:
void foo(char *&p)
{
p = (b == true)? new char[10] : 0;
}
But I am not able to get what is the use case for T* const& kind of pointer (since that pointer is not changeable)? I mean why should not I pass simply T* const ?
void foo(char* const &p); // p is not changeable
void foo(char* const p); // p is not changeable
You would use a T* const & as a parameter if the value of the pointer object might be changed by something external to your function and you wanted to be able to observe changes to the value of the pointer object or if you wanted to store a reference or pointer to the pointer object for later reading.
A T* parameter (equivalent to T* const as a function parameter) just gives you a copy of the pointer object, a snapshot of its value when it was passed to your function.
void foo( char* const& ptr )
{
char* p1 = ptr; // initial value
global_fn(); // ptr might be changed
char* p2 = ptr; // new value of ptr
}
vs
void foo2( char* ptr )
{
char* p1 = ptr; // initial value
global_fn(); // ptr can't be changed, it's local to this function
char* p2 = ptr; // will be the same as p1
}
Technically, even the function itself might change the value of the pointer to which it is passed a reference.
E.g.
char* p;
std::ptrdiff_t foo( char* const& ptr )
{
++p;
return p - ptr; // returns 0, would return 1 if the parameter was by value
}
int main()
{
char test[] = "Hello, world!";
p = test;
foo( p );
}
The difference is realistically nil. const references are used to prevent copying of expensive-to-copy or, in generic code, uncopyable types, but since pointers are trivial, it's negligible and you may as well take by value.
I think a simpler example would illustrate the point that Charles Bailey is making. Let's remove the issue of the pointer part of it, because for this question it is irrelevant. So your question basically becomes:
void foo(const int &p); // p is not changeable
void foo(const int p); // p is not changeable
Do you see more clearly how it works? Yes, the local variable "p" cannot be assigned to in both cases. And yes, neither piece of code will affect the variable in the calling scope. But in the former example p could be a reference to a variable (non-const) int that can be changed while the latter is an argument passed by value which could not be changed. (Actually the const in the second example has no effect on anything outside the function, so it is kind of superfluous. Same with the second example in the question.)
When I read litb answer to this question, I learned that passing an array by reference allows us to obtain its size. I just played little bit with code, and tried to pass a "function" by reference and surprisingly (at least for me), this code compiles:
void execute( void (&func)() ) // func is passed by reference!
{
func();
}
Is there any difference between the last function, and this one:
void execute( void (*func)() ) // func is passed by pointer!
{
func();
}
I tried it using VC2008, and it produces different output in each case. The strange thing is that the compiler optimizes the code better in case of a function pointer:
void print()
{
std::cout << "Hello References!";
}
void execute( void (&func)() ) // optimized
{
func();
}
int main()
{
00291020 call print (291000h)
}
=========================================
// In this case, the compiler removes all function calls in the code!
void print() // optimized!
{
std::cout << "Hello Pointers!";
}
void execute( void (*func)() ) // optimized
{
func();
}
int main()
{
002F1005 push offset string "Hello References!" (2F2124h)
002F100A push eax
002F100B call std::operator<<<std::char_traits<char> > (2F1150h)
}
There has to be a difference, although I don't see it, right?
Note: the code was compiled using VC2008, with /O2 and /Ot turned on.
EDIT:: I am really interested about any difference between function references and function pointers. I examined the produced assembly code just to see how it is translated in each case.
For the language difference (keeping only the function declarations below, since that's what's important only)
void execute( void (&func)() );
void g();
int main() {
void (*fp)() = g;
execute(fp); // doesn't work
execute(&g); // doesn't work either
execute(g); // works
}
It doesn't work, because it wants a function, not a function pointer. For the same reason that array answer rejects a pointer, this rejects a pointer too. You have to pass "g" directly.
For templates, it matters too
template<typename T>
void execute(T &t) { T u = t; u(); }
template<typename T>
void execute(T t) { T u = t; u(); }
Those two are very different from one another. If you call it with execute(g); like above, then the first will try to declare a function and initialize it with t (reference to g). The generated function would look like this
void execute(void(&t)()) { void u() = t; u(); }
Now you can initialize references and pointers to functions, but of course not functions itself. In the second definition, T will be deduced to a function pointer type by template argument deduction, and passing a function will convert it to that pointer parameter type implicitly. So everything will go fine.
I don't know why MSVC treats them differently for inlining - but i also suspect it's because function references appear more seldom.
It's not as common an idiom, so it might just be that the VS team didn't add a rule to optimise it.
I think it is due to the C++ Standard 4.3:
An lvalue of function type T can be converted to an rvalue of type “pointer to T.” The result is a pointer to
the function.
The difference between a reference(&) and pointer(*) is that the reference provides the address of the variable or the location, and the pointer points to the location in memory of the address stored in it.
int *pointer;
int variable;
pointer = &variable; // assigning the address of variable to pointer
variable = 53; // value of variable
cout << *pointer; // This should output the value of the address where is pointing, in this
// case 53, that is the value of variable to where is pointing.
We can conclude that the (&variable) have the address of that memory location and *anyname points to the address stored in its memory...