I am kind confused about this case:
Declare a pointer:
int b =10;
int*a=&b;
Here & takes the address of b.
Consider another example:
/* Reference to the calling object can be returned */
Test& Test::func ()
{
// Some processing
return *this;
}
this should be a pointer, *this is the obeject pointed.
But here we are asking to assign *this to &Test.
What should we modify the code to let the function return the address. Should we still use Test& ?
In C++ there're two different syntax units:
&variable; // extracts address of variable
and
Type& ref = variable; // creates reference called ref to variable
Easy usage example:
int v = 5;
cout << v << endl; // prints 5
cout << &v << endl; // prints address of v
int* p;
p = &v; // stores address of v into p (p is a pointer to int)
int& r = v;
cout << r << endl; // prints 5
r = 6;
cout << r << endl; // prints 6
cout << v << endl; // prints 6 too because r is a reference to v
As for using references in functions, you should google "passing by reference in C++", there're many tutorials about it.
Firstly, this is a pointer. The * dereferences the pointer, meaning return *this; returns the object, not a pointer to it.
Secondly, Test& is returning a reference to a Test instance. In your case, it is a reference to the object. To make it return a pointer, it should be Test*.
It makes more sense if you read a pointer declaration from right to left.
Test* func(); //When I call func, and dereference the returned value, it will be a Test
But here we are asking to assign *this to &Test.
No... you're asking for the value/expression *this to be used to return a Test&, which is a reference to a Test object. What that does is return a reference to the object on which func() is invoked.
What should we modify the code to let the function return the address. Should we still use Test& ?
You should use Test* instead... pointers are addresses, and having changed the return type you could return this (which is a pointer), but not *this because *this is not a pointer.
Related
I've been carefully studying C++ catogories recently. The difference between lvalue and rvalue seems to be clear, but I got confused when it comes to prvalue and xvalue.
Given the example below:
#include <iostream>
using std::cout;
using std::endl;
using std::move;
class Type {
public:
int value;
Type(const int &value=0) :value(value) {}
Type(const Type &type) :value(type.value){}
Type(Type &&type) noexcept :value(type.value) {}
Type &operator= (const Type &type) {
value = type.value;
return *this;
}
Type &operator=(Type &&type) noexcept{
value = type.value;
return *this;
}
};
Type foo1(const Type &value) {
return Type(value);
}
Type &&foo2(const Type &value) {
return Type(value);
}
int main() {
Type bar1(123);
cout << foo1(bar1).value << endl;
cout << foo2(bar1).value << endl;
Type bar2;
bar2 = foo1(bar1);
cout << bar2.value << endl;
bar2 = foo2(bar1);
cout << bar2.value << endl;
return 0;
}
Running the example, the console puts:
123
123
123
-858993460
Can anyone explan why it gives an unexpected value in the last output?
What feature does this example show about xvalue?
foo2 is returning reference bound to temporary which is destroyed immediately; it always returns a dangled reference.
a temporary bound to a return value of a function in a return statement is not extended: it is destroyed immediately at the end of the return expression. Such function always returns a dangling reference.
Dereference on the returned reference like foo2(bar1).value and bar2 = foo2(bar1); leads to UB; anything is possible.
On the other hand, foo1 doesn't have such issue. The return value is moved from the temporary object.
Here's a very simple explanation. Consider this textbook example from pre-C++0x times:
T& f()
{
T t;
return t;
}
// ...
T& val = f();
cout << val; // <--- SIGSEGV here
You are not surprised that this snippet crashed, right? You returned a reference (which is, under the hood, nothing more than a glorified pointer) to a local object which was destroyed before the function even returned, thus dooming val to become a dangling reference.
Now consider:
T&& f()
{
T t;
return static_cast<T&&>(t);
}
// ...
T&& val = f();
cout << val; // <--- SIGSEGV here
In terms of object lifetimes, this is exactly the same as before. Rvalue reference is not some brand new tool for magically moving objects around. It's the same old reference (read: glorified pointer). Nothing changed - you still returned an address of a destroyed object.
And I assume everyone is on board with that std::move is nothing more than a glorified static_cast<T&&>, so in case it's used the result is the same:
T&& f()
{
T t;
return std::move(t);
}
// ...
T&& val = f();
cout << val; // <--- SIGSEGV here
This example is 99.9% identical to the previous one.
(The 0.1% difference is, e.g., in that in the first two examples GCC knows that the code is screwed up and actually returns a null reference that's guaranteed to crash on first use; while in the last example, since std::move is a function, it can't be sure so it obediently returns the bad address).
I got some code look like this
struct A
{
int i;
A(int i) : i(i) {}
~A()
{
cout << "destroy " << i << endl;
}
};
using p = shared_ptr<A>;
p f(int i)
{
return make_shared<A>(i);
}
int main()
{
auto i = f(1);
cout << "a" << endl;
p && j = f(2);
cout << "a" << endl;
p && k = move(f(3));
cout << "a" << endl;
auto l = move(f(4));
cout << "a" << endl;
p ptr = make_shared<A>(5);
auto && a = move(ptr);
cout << "a" << endl;
}
and the output is
a
a
destroy 3
a
a
a
destroy 5
destroy 4
destroy 2
destroy 1
I don't understand why move a function's return value to a rvalue reference cause destruction. But put it directly to a rvalue reference is ok.
The problem is actually found with std::get<> of a std::tuple. I have a function that return a tuple of two shared_ptr and use std::get<> to access the element. But I found that auto && i = get<0>(f()) will cause error but auto i = get<0>(f()) won't. Then I find a similar but simpler situation for std::move
p && j = f(2);
Here, f returns a prvalue of type std::shared_ptr<A>. When you bind a reference to a prvalue it extends the lifetime of the prvalue to be that of the reference. That means that the object returned by f will have the same lifetime as j.
p && k = move(f(3));
Here, once again f returns a prvalue. std::move's parameter binds to that prvalue, extending its lifetime to the lifetime of the parameter. std::move does not return a prvalue though. It returns an xvalue. Lifetime extension does not apply to xvalues, so the object returned by f gets destroyed as soon as std::move's parameter's lifetime ends. That is, it gets destroyed when std::move returns. k then becomes a dangling reference.
Let’s go through these one by one:
auto i = f(1); // (1)
This creates a local variable i (not a reference) initialized with the return value of f(1). This is OK. The lifetime of i is until the end of the block.
p && j = f(2); // (2)
This initializes the reference j with a reference to the object returned by f(2), and this extends the lifetime of the value returned by f(2), so this is OK. The lifetime of j is until the end of the block.
p && k = move(f(3)); // (3)
This initializes the reference with a reference to the object returned by move, no lifetime extension occurs since the value returned by move is a reference to the temporary returned by f(2) (and not a temporary object), but the temporary returned by f(2) dies as soon as k is initialized, since its lifetime is not extended (it’s not assigned to a reference variable), and k ends up being a dangling reference.
auto l = move(f(4)); // (4)
Same as (1), the move is useless. The lifetime of l is until the end of the block.
p ptr = make_shared<A>(5); // (5)
This is a local variable initialization. The lifetime of ptr is until the end of the block.
auto && a = move(ptr);
a is a reference to ptr. This does not change the lifetime of ptr.
Because by using std::move you've turned the return value into a reference. And not a const reference, so it's a temporary.
So no copy takes place and as soon as the line ends, the return value is destroyed.
I am currently taking a data structures and algorithms class and my professor gave us material that included functions that take in pointer values and pointer/reference values.
These functions would look like this:
int function1(int a); // Pass by value
int function2(int &ref); // Pass by reference
int function3(int* ptr); // This will take in a pointer value
int function4(int*& ptr); // This will take in a pointer/reference value
I understand the difference between pass by value, and pass by reference. I also have tried implementing both of the latter two examples as basic functions, but I am not entirely sure how these two arguments differ from pass by reference or how they differ from each other.
Could somebody explain how these two functions parameters work and how they could be used practically?
[...] but I am not entirely sure how these two arguments differ from
pass by reference or how they differ from each other.
In the first function
int function3(int* ptr);
// ^^^^
you pass the pointer to an int by value. Meaning int* by value.
In second one,
int function4(int*& ptr);
// ^^ --> here
you pass the pointer to the int by reference. Meaning you are passing the reference to the int* type.
But how does passing the pointer by value and by reference differ in
usage from passing a regular variable type such as an integer by value
or reference?
Same. When you pass the pointer by value, the changes that you do the passed pointer(ex: assiging another pointer) will be only valid in the function scop. On the otherside, pointer pass by reference case, you can directly make changes to the pointer in the main(). For example, see the folloiwng demonstration.
#include <iostream>
// some integer
int valueGlobal{ 200 };
void ptrByValue(int* ptrInt)
{
std::cout << "ptrByValue()\n";
ptrInt = &valueGlobal;
std::cout << "Inside function pointee: " << *ptrInt << "\n";
}
void ptrByRef(int *& ptrInt)
{
std::cout << "ptrByRef()\n";
ptrInt = &valueGlobal;
std::cout << "Inside function pointee: " << *ptrInt << "\n";
}
int main()
{
{
std::cout << "Pointer pass by value\n";
int value{ 1 };
int* ptrInt{ &value };
std::cout << "In main() pointee before function call: " << *ptrInt << "\n";
ptrByValue(ptrInt);
std::cout << "In main() pointee after function call: " << *ptrInt << "\n\n";
}
{
std::cout << "Pointer pass by reference\n";
int value{ 1 };
int* ptrInt{ &value };
std::cout << "In main() pointee before function call: " << *ptrInt << "\n";
ptrByRef(ptrInt);
std::cout << "In main() pointee after function call: " << *ptrInt << "\n\n";
}
}
Output:
Pointer pass by value
In main() pointee before function call: 1
ptrByValue()
Inside function pointee: 200
In main() pointee after function call: 1
Pointer pass by reference
In main() pointee before function call: 1
ptrByRef()
Inside function pointee: 200
In main() pointee after function call: 200
Passing a pointer by reference allow you to change the pointer and not only the pointed value. So if you do and assignment of pointer in the function int function4(int*& ptr) in this way :
ptr = nullptr;
the caller have the pointer set to "nullptr".
In the function int function3(int* ptr) the pointer passed is copied in the variabile ptr that is valid only in the scope of function3. In this case you can only change the value pointed by the pointer and not the pointer ( or to better specify you can change the pointer but only in the scope of the function ). So the previous expression ptr = nullptr; has no effect in the caller.
If you want to modify an outside int value, use this:
int function1(int* ptr) {
*ptr = 100; // Now the outside value is 100
ptr = nullptr; // Useless. This does not affect the outside pointer
}
If you want to modify an outside int* pointer, i.e. redirect that pointer, use this:
int function2(int*& ptr) {
ptr = nullptr; // Now the outside pointer is nullptr
}
Or this:
int function3(int** ptr) {
*ptr = nullptr; // Same
}
The first and second are pass by value and reference respectively as commented in the code.
The third one takes an integer pointer as a parameter by value, which can be assigned a memory location but the value of the pointer only changes locally inside the function scope.
The fourth one holds the value of an integer variable with reference as there is an amperson(&) for referencing the value(which is a pointer).
They are function declarations, not definitions so unless they are defined with a function body you can't explore its practical uses. (or a list of endless possibilities from what you could do with an integer value)
If you want a case of pass by value vs pass by reference, the classic example would be the swapping of two or more values within a function (without returning values), wherein pass by reference works and pass by value fails or your first and third functions would change the values locally inside the function only whereas the second and fourth ones would change the value in its entirety.
#include <iostream>
using namespace std;
int& fun1(int& ref)
{
ref = 30;
return ref;
}
int main()
{
int i = 10;
i = fun1(i);
cout << "Value of i:" << i << endl;
return 0;
}
Output:
Value of i:30
Is it valid to return a function argument passed as reference as a function return the same reference?
According to my understanding ref in fun1(int& ref) will have a it's own memory location in the stack and returning the address of ref is invalid.
References act in every way as if they were the original object. This means that taking the address of a reference gives the address of the original object and taking a reference to a reference gives a reference to the original object.
While there exists pointers to pointers, there is no such thing as a reference to a reference.
Take note the assignment in i = fun1(i); is redundant. i is already 30 in this case. You can simply call fun1(i);.
Yes, it's fine. What matters is that the lifetime of the referent is long enough.
I typed the following example:
#include <iostream>
double f(double* x, double* y)
{
std::cout << "val x: " << *x << "\n";
std::cout << "val y: " << *y << "\n";
return *x * *y;
}
double f2(double &x, double &y)
{
std::cout << "val x: " << x << "\n";
std::cout << "val y: " << y << "\n";
return x * y;
}
int main()
{
double a, b;
a = 2;
b = 3;
std::cout << f(&a, &b) << "\n";
std::cout << f2(a, b) << "\n";
return 0;
}
In the function f I declare x and y as pointers of which I can get the value by using *x. When calling f I need to pass the address of my passed arguments, that is why I pass &a, &b. f2 is the same except the definition is different.
Now my question is: Are they both really the same concerning memory management? Both not making any copy of the passed value but instead passing a reference?
I wonder about f2 because I couldn't read out the address of x in f2 so I know more about x and y in f (there I know address AND value).
Edit: After doing some more research, I found a quite useful topic:
Pointer vs. Reference
There's also a link to google coding guidelines http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments which is quite useful I feel (as I understood now, it's a form of subject taste) to make more clear
f2 is taking it's arguments by reference, which is essentially an alias for the arguments you pass. The difference between pointer and reference is that a reference cannot be NULL. With the f you need to pass the address (using & operator) of the parameters you're passing to the pointer, where when you pass by reference you just pass the parameters and the alias is created.
Passing by const reference (const double& ref) is preferred when you are not going to change the arguments inside the function, and when you are going to change them, use non-const reference.
Pointers are mostly used when you need to be able to pass NULL to your parameters, obviously you'd need to check then inside your function if the pointer was not NULL before using it.
This is just syntactic sugar to avoid having to use * everytime you reference the argument. You still can use & to have the address of x in f2.
In my head, parameters of functions are always passed by value. Passing an int is easy to imagine, passing a double is just bigger and passing a struct or class could be very big indeed.
But passing a pointer to something, well, you're just passing an address by value. (A pointer is often a convenient size for the CPU just like an int.)
A reference is very similar, and certainly I think of a reference as a pointer, but with syntactic sugar to make it look like the object its referring to has been passed by value.
You can also think of a reference as a const pointer, ie:
int i;
int j;
int* p = &i; // pointer to i
int* const cp = p; // cp points to i, but cp cannot be modified
p = &j; // OK - p is modified to point to j
*cp = 0; // OK - i is overwritten
cp = &j; // ERROR - cp cannot be modified
int& ri = i; // ri refers to i
ri = 1; // i is overwritten
ri = j; // i is overwritten again
// Did you think ri might refer to j?
So, a pointer does double time: It is a value in its own right, but it can also point to another value when you dereference it, eg: *p.
Also, having reference parameters means that you cannot make them refer to anything else during the lifetime of the function because there's no way to express that.
A reference is supposed not to be able to be initialised with null, but consider this:
void foo(int& i);
int* p = 0;
foo(*p);
This means that pointers should be checked before you use them, but references cannot be checked. The implementation of foo() could try to read from or write to i which will cause an access violation.
In the above example the pointer p should have been checked before being used in the call to foo:
if (p) foo(*p);
Another difference that hasn't been mentioned is that you cannot change what a reference refers to. This doesn't make a lot of difference in the function call example shown in the original question.
int X(10), Y(20);
int *pX = X;
int& rY = Y;
*pX = 15; // change value of X
rY = 25; // change value of Y
pX = Y; // pX now points to Y
rY always points to Y and cannot be moved.
References can't be used to index into simple arrays like pointers.
You should have been able to read x address in both functions.
To do so in f2, you must of course prefix x by a & since there, x is a reference to a double, and you want an address.
A worth noticing difference between references and pointers is that the former cannot be NULL. You must pass something (valid) while when providing a pointer, you must specify in the documentation if passing NULL is allowed/well defined.
Another difference is a matter of readability: using references instead of pointers (when possible) makes the code less cluttered with * and ->.