Temporary objects are sometimes created in C++. One example from the STL valarray class would be the slice_array, which is invoked every time a series of indices of a valarray is selected.
http://www.cplusplus.com/reference/valarray/slice_array/
My question is this:
When passing these temporary objects as arguments to a function, is a copy of these objects passed, or only a reference?
E.g. imagine these two naive functions:
double simple_product(double* inp,int length){
double res=1;
for(int i=0;i<length;++i){
res = res*inp[i];
}
return(res);
}
double sum_selected(valarray<double> v){
simple_product(&v[0],v.size());
return(v.sum());
}
If I call them in the following fashion:
valarray<double> valery(10,10);
size_t sel[] = {1,3,4};
valarray<size_t> selection (sel,3);
cout << sum_selected(valery[selection]);
will a new object with a size of 3*size_t be temporarily created within the stack of the function sum_selected or not?
Please note that declaring the function as: double sum_selected(valarray<double> & v)
is not permitted (temporary objects can only be bound to const references).
The reason why this is interesting is that, for example here, it is not possible to declare the function as:
double sum_selected(const valarray<double> & v), because then the function simple_product (which is to be assumed unalterable) cannot be called. However, making a temporary copy of the passed argument would be problematic for memory in case of big arrays.
If the function is declared to take its argument by value, then it's passed by value, creating a new copy of the object:
void f(thing t); // pass by value
If it's declared to take its argument by reference, then it's passed by reference. But it can only take a temporary by const or rvalue reference:
void f(thing const & t); // OK: const lvalue reference
void f(thing && t); // OK: rvalue reference
void f(thing & t); // Error: lvalue reference can't bind to temporary
Passing by reference doesn't create a new object, and the lifetime of the temporary is such that it's valid during the function call, until the end of the statement that creates it.
valarray<T>::operator[](valarray<size_t> const&) returns an indirect_array<T> (reference), or a valarray<T> for the const-qualified operator, not a slice_array.
If you want to be able to access the selected elements as a contiguous array, then you'll need to collect them into a contiguous array. The converting constructor valarray<T>::valarray(indirect_array<T> const&) does this for you. Reference semantics would be useless in this case, as there is no existing object that has your desired elements arranged contiguously.
Changing the function signature to double sum_selected(valarray<double> const&) would make no difference to your code, as a temporary valarray<double> is constructed anyway. It would be more efficient in the case where valery is passed directly, without subscripting.
Related
I have the following code:
//void func(const std::string &&i){
//void func(const std::string &i){
void func(const std::string i){
std::string val{i};
}
int main()
{
std::string d = "asdf";
func(std::move(d));
std::cout << d << std::endl;
}
When i is pass-by-value, d becomes empty, but d retains its form if we're passing by reference or by r-value reference. Could someone explain what is going on?
I understand that std::move doesn't actually move anything, but rather makes the variable it takes in moveable by casting it to an xvalue.
As an aside why does the code in the current state compile if d is cast to an x-value? func is currently set to take in pass by value arguments, and not by rvalue reference.
When i is pass-by-value, d becomes empty,
To be accurate, d will be in some valid state not specified in the C++ standard. Empty is one possibility.
std::move itself never causes the move constructor to be called directly. Neither does binding an rvalue reference to an object cause move constructor to be called directly.
Only initialising an object with a non-const rvalue will cause the argument to be moved from. In the example, std::string i is initialised with a non-const rvalue and the move constructor will be called.
As an aside why does the code in the current state compile if d is cast to an x-value?
Because the type has a (non-deleted) move constructor. Therefore the argument can be initialised from an rvalues.
I had thought if we had std::string i, a copy of the rvalue reference is made.
std::string i is not a reference. It is a variable of type std::string and as such there is an object of type std::string associated with the variable. That object is initialised with the expression that is passed into the function as argument.
Also, if I observe that the output of d is still the same as prior to applying std::move, what does this mean in this case?
If you call the uncommented version of the function with an rvalue, then the argument will be moved from. If the value is same as it was, then it simply means that the value is the same. You cannot assume that the value will be the same nor that it won't be the same.
Does it mean that d is still occupying the space it originally occupied?
Assuming that by "space" you mean the storage where the variable is, then of course it is still occupying the same storage. The address of an object never changes through the lifetime of the object.
void func(const std::string &&i)
This signature will not move anything, because the reference is to a const object. Remove the const, and it'll work. But only if you std::move the parameter i again inside the function. This is because anything that has a name is an lvalue, whether the parameter was declared as & or &&. See this answer.
void func(const std::string &i)
This will copy, as you probably already know. However, it behaves similarly to the ptevious one in that if you drop the const and do std::move( i ) inside the function, it'll actually move. This is because, as you noted, move is a cast and the compiler will listen to you and do exactly what you say when you cast, regardless of what you intended.
void func(const std::string i)
This moves in your example because here, i is an entirely new string. The outside string d gets moved into i. However, you still have to drop the const and use std::move( i ) if you want to move i into val.
I know this is silly and the title probably isn't the answer..
I always thought of this as a pointer to the current object which is supplied in every method call from an object (which is not a static method)
but looking at what my code actually returns for example:
Test& Test::func ()
{
// Some processing
return *this;
}
the dereference of this is returned... and the return type is a reference to the object.... so what does that make this? Is there something under the hood I'm not understanding well?
Remember that a reference is simply a different name for an object.
That implies that returning a reference is the same thing as returning an object on type level of abstraction; it is not the same thing in the result: returning a reference means the caller gets a reference to the current object, whereas returning an object gives him (a reference to) a copy of the current object - with all the consequences, like the copy constructor being called, deep copy decisions are being made, etc.
From cppreference:
The keyword this is a prvalue expression whose value is the address of the object, on which the member function is being called.
And then (perhaps easier to grasp):
The type of this in a member function of class X is X* (pointer to X). If the member function is cv-qualified, the type of this is cv X* (pointer to identically cv-qualified X). Since constructors and destructors cannot be cv-qualified, the type of this in them is always X*, even when constructing or destroying a const object.
So, this is not a pointer to a reference, but just a pointer.
Actually you cannot have a pointer to a reference, because taking the address of a reference will give you the address of referenced object.
Further, there is no special syntax in C++ to form a reference. Instead references have to be bound on initialization, for example:
int x = 3;
int& y = x; // x is int, but y is int&
assert( &y == &x); // address of y is the address of x
Similar when returning a reference from a function:
int& get_x() {
static int x = 3;
return x;
}
To put it simply:
test t1; // t1 is a test object.
test& t2 = t1; // t2 is another name for t1.
test* t3; // t3 holds an address of a test object.
*t3; // derefernce t. which gives you, the test object that t3 points to.
this is a pointer to the current test object.
therefore *this is the current test object, and because the return value type is test&, when you call the function, you get the same object you called the function from.
I have a class taking variables by reference. A function in the class needs to call another function that prints the object. The question arises when passing reference object from process() to disp(). Can I pass a reference from one function to another function? How to accomplish this using reference and what are best practices in such cases?
(I know one can take other approaches, such as using pointers or passing by value to class. But, I want to know solution with reference.)
class Abc
{
double &a, &b;
public:
Abc(double &var1, double &var2): a(var1), b(var2) {}
void process()
{
//call disp()
disp(a); //Question
}
void disp(double &var)
{
std::cout << var;
}
};
int main()
{
double x=2.2, y=10.5;
Abc obj1(x,y);
obj1.process(); //question
return 0;
}
Can I pass a reference object to a function?
Pedantic point: There is no such thing as a "reference object". References are not objects.
But yes, it is possible to pass a reference to a function.
The question arises when passing reference object from process() to disp()
You already pass a reference there. That part of the program is correct.
You do have a problem here:
Abc::Abc(double&, double&);
float x=2.2, y=10.5 // anohter bug: probably intended to have a semicolon here
Abc obj1(x,y);
When object of one type (float) is bound to a reference of another type that is not related through inheritance (double&), the operand is converted to the target type (double). The result of the conversion is a temporary r-value. Non-const l-value references cannot be bound to r-values so therefore the program is ill-formed.
Even if the reference could be bound (for example, if you use a language extension that allows it, or if you used const references instead), the lifetime of the temporary would only extend for the lifetime of the reference variable which it was bound to, which is the argument of the constructor. After the constructor was finished, the member references would be referring to the temporary whose lifetime has already ended and therefore using those references would have undefined behaviour.
Simple solution: Use variables of same type as the reference: double x=2.2, y=10.5.
I am learning C++ and was reading a book on it where I came across this:
struct Vector{
int size;
double* elem;
}
void vector_init(Vector& v, int s){
v.size = s;
v.elem = new double[s];
}
So here, would void vector_init(Vector v, int s), without the reference operator, be wrong? Do I have to manually pass by reference using & while passing objects, structs, arrays or anything else as parameters? Also are there any alternate ways to do this? like say void vector_init(Vector *v, int s)?
Any help is appreciated.
There is no "reference operator".
The & declarator only gets added to the function parameter you want to be passed by reference. Passing a reference argument looks identical to passing by value.
would void vector_init(Vector v, int s), without the reference operator, be wrong?
If you don't pass v by reference, a copy of v will be made when enters function vector_init and you operate on that copy. After vector_init returns that temporary copy will be destroyed, so vector_init has no effect to your original v. To manipulate on original v, you need to pass v by reference(same to other type).
Also are there any alternate ways to do this? like say void vector_init(Vector *v, int s)?
Pass by reference is better choice compare to pass by pointer.
Actually passing a value by reference (void vector_init(Vector &v, int s)) or by pointer void vector_init(Vector *v, int s) have basically the same meaning.
The main difference is that when you pass by reference you are forced to pass a valid parameter (NULL wouldn't work) and that when you pass by pointer you must explicitly convert your argument to a pointer (while this is automatically done when passing by reference)
When you pass something by value as in void vector_init(Vector v, int s) it's different: the argument is copied through copy constructor and every modification made inside the scope of the function is local to the local copy of the argument, you cannot modify the original argument through a pass by value. You are not really passing your variable, you are passing a copy of it.
This even means that, if the argument is a large class or struct or has an expensive copy constructor, then also performance issues can occur.
I have just started C++ and have come across references and have not understood completely.
References , as i read is an alternative name for an object.Why use that instead of directly accessing the object as any operation on references is directly reflected on the object ...?
Why and when are they used ?
Is ist like a constant pointer that is referenced each time it is used ... ?
And , it says
double& dr = 1; ---- says it is an error (some lavalue needed)
const double& cdr = 1; ---- says it is ok.
i dont understand it properly..So please explain why it is so ...
Thank You...:)
Why use that instead of directly
accessing the object as any operation
on references is directly reflected on
the object ...?
C++ passes parameters by value, meaning if you have a function such as:
void foo(MyObject o) { ... }
By default C++ will make a copy of a MyObject, not directly use the object being passed in. So, one use of references is to ensure you are working on the same object:
void foo(MyObject &o) { ...}
Or, if you aren't modifying o:
void foo(const MyObject &o) { ... }
References are another way of what was originally in C code like this
void fubarSquare(int *x){
int y = *x;
*x = y * y;
}
// typical invocation
int z = 2;
fubarSquare(&z);
// now z is 4
with references in C++ it would be like this
void fubarSquareCpp(int& x){
x = x * x;
}
// typical invocation
int z = 2;
fubarSquareCpp(z);
// now z is 4
It's a neater syntactical way of using a call-by-reference parameter instead of using the C's notation asterisk/star to indicate a pointer and as a call-by-reference parameter...and modifying the parameter directly outside of the function...
Have a look at Bjarne Stoustrap's page here which covers how C++ is and also here on the technical faq here
A reference is basically a pointer that looks like an object. It is very very hard to get a NULL reference though you can go through hoops and create one.
With regards to your example, 1 is an rvalue or a result. It is just a temporary variable and can not be modified. Thus you can't take a non const reference to it. However you can take a const reference to it. This means you can't change the value of the reference.
Here is an example of creating a NULL reference. Don't do it!
int * x = (int *)NULL;
int & y = *x;
I agree with you. using references as just an alias name is not very useful.
It is more useful if you consider it as an immutable pointer. But not that useful in fact.
Practically, it is used to define clean interfaces. For example when you define:
int foo(const int& param);
You say that param is a read-only parameter in foo.
Do not forget that you MUST assign a value to a reference.
See the C++ faqlite on references for more
my2c
References improve the syntax, so no pointer dereference needed.
Assuming Base is a class that may be derived from:
void someFunction(Base b)
{
b.function();
// b is a copy of what was passed - probably performance issues
// possible unintended object slicing - you only get the Base part of it
// no virtual function call
// no changes to b visible outside the function
}
void someFunction(Base* b)
{
b->function();
// a shortcut for (*b).function();
// b is the same object that was passed to the function
// possible virtual call
// changes visible outside the function
}
void someFunction(Base& b)
{
b.function();
// b is the same object that was passed to the function
// possible virtual call
// changes visible outside the function
}
References are like constant pointers (NOT pointers to constants - i.e. you can change the object, but you can't change to what you're pointing). const reference is a reference through which you can do things that can be done on const object.
References are also good, because you can't have a null reference
Give the wikipedia article a good read through. To sum it up, references are more friendly version of pointers which are commonly used to pass objects as references into functions without worrying about a null pointer.
To explain the example:
Think of the number 1 represented as a variable. When compiled, this number is put into the global section of the memory which can be referenced by the program, but not modified.
So it is of type: const int
double &dr = 1 is trying to assign dr (a reference to a double) to the const int 1. Since 1 is a constant, the compiler will not allow you to make a non-constant reference to it.
In the second line:
const double &dr = 1 is trying to assign dr (a constant reference to a double) the const int 1. This works because the reference is also const and therefore can point to a const int.
EDIT
The const int is converted to a const double before assigned.
References are language entitities that represent another object they refer to. Nonconst references are lvalues, and must be initialized with an lvalue. They can be useful like this:
int& x=condition ? array[1] : array[2];
int& y=condition ? array[0] : array[3];
x+=y;
y=0;
When used as a function parameter, they tell the caller he has to pass an lvalue that might be written to by the function:
void set1(int& x) { x=1; }
int foo;
set1(foo); // ok, foo is 1
set1(foo+1); // not OK, not lvalue
Const references, on the other hand, can be bound to rvalues. In function parameters, they are usually used to avoid excessive copies:
void niceness(std::string s); // the string would be copied by its copy-ctor
void niceness(const std::string& s); // the caller's string would be used
Note that this may or may not yield faster code.
When const-references are used in normal code, they can bind rvalues, too, and as a special rule, they extend the lifetime of the object they are bound to. This is what you saw in your code:
const double& d=1; // OK, bind a rvalue to a const-ref
double& d=1; // Bad, need lvalue
All references are polymorphic, like pointers:
class A { virtual void f(); }
class B : public A { void f(); }
B b;
A& ar=b;
ar.f(); // calls B::f()
and all references are aliases like pointers:
int f(int& a, const int& b)
{
a=1;
return b;
}
int x;
f(x, 42); // ==42, foo=1
x=42;
f(x, x); // ==1 (not 42), foo=1
double& dr = 1; // 1.0 would be more clear
Is invalid because 1 is viewed to be of type const double so if you want a reference to that variable you need to have a reference to a const double so
const double& dr = 1.0;
Is correct.
Utility of references is most visible in the context of passing parameters to functions.
I.e,
int a;
func definition: void foo (int& param) {param = 1;}
func call: foo(a);
The way as 'param' aliases 'a' is clean and its intention is easily understood by a reader of this code as well as compiler that may optimize away when inlining any additional memory allocation needed for the reference.
Passing a reference to a function and then having the function use the reference is almost like passing a pointer to the function and then having the function dereference the pointer. In many cases, the machine-code implementation will be identical. There are some differences, though, especially in the case of functions that get expanded inline. If a variable is passed by reference to an inline function, the compiler will often be able to substitute the variable itself--even if stored in a machine register--when expanding the function. By contrast, if one takes the address of a variable and passes that as a pointer to a function which then dereferences it, the compiler is less likely to figure out that optimization unless it determines not only that--at least for one particular expansion of the function--the pointer will always point to that variable, but also that the pointer will not be used anywhere else (if the pointer was used elsewhere, the variable could not be kept in a register).