Is a copy made when passing by 'implied'(?) reference in C++ - c++

If I have a function that takes a reference to a map:
pair<int,int> myFunc(map<int,char> &myVar){...}
I can pass it a map without needing the '&'.
myFunc(someMapitoa);
Is there any difference? Is a copy made and then thrown away? Should I use the '&' anyway?

C++ is pass-by-value by default.
So, this makes a copy:
void foo (bar b);
This does not:
void foo (bar & b);
This makes a copy of a pointer, but not the actual data that it points to:
void foo (bar * b);
If you really want to get deeper into it then see this SO post about move semantics.
Anyway, for the above three examples they are all called the same way:
#include <iostream>
using namespace std;
int alpha (int arg) {
// we can do anything with arg and it won't impact my caller
// because arg is just a copy of what my caller passed me
arg = arg + 1;
return arg;
}
int bravo (int & arg) {
// if I do anything to arg it'll change the value that my caller passed in
arg = arg + 1;
return arg;
}
int charlie (int * arg) {
// when we deal with it like this it's pretty much the same thing
// as a reference even though it's not exactly the same thing
*arg = *arg + 1;
return *arg;
}
int main () {
int a = 0;
// 1
cout << alpha (a) << endl;
// 1
cout << bravo (a) << endl;
// 2
cout << charlie (&a) << endl;
return 0;
}

You should think of this in terms of what is being initialized from what.
When you call a function, each argument is used to initialize the corresponding parameter. If the parameter is declared with reference type, it's a reference. If the parameter is not declared with reference type, it's an object.
The initialization of a reference to class type T from an expression of type T never makes a copy.
The initialization of an object of class type T from an expression of type T either copies or moves.
The rules here are the same as the rules for initializing non-parameter variables, as in:
T t = ...
T& r = ...
The fact that a function may take a reference to an argument even when there is no explicit notation at the call site is viewed by some as confusing. This is why some style guides ban non-const reference parameters (such as the Google C++ style guide) and force you to declare the argument as a pointer so that & must be used at the call site. I don't advocate this coding style, but it is an option you might want to consider.

Related

Does pass-by-reference decay into pass-by-pointer in some cases?

I've looked for an answer to this one, but I can't seem to find anything, so I'm asking here:
Do reference parameters decay into pointers where it is logically necessary?
Let me explain what I mean:
If I declare a function with a reference to an int as a parameter:
void sum(int& a, const int& b) { a += b; }
(assuming that this won't be inlined)
The logical assumption would be that calling this function can be optimized by not passing any parameters, but by letting the function access the variables that are already on the stack. Changing these directly prevents the need for passing pointers.
Problem with this is that (again, assuming this doesn't get inlined), if the function is called from a ton of different places, the relevant values for each call are potentially in different places in the stack, which means the call can't be optimized.
Does that mean that, in those cases (which could potentially make up the majority of one's cases if the function is called from a ton of different places in the code), the reference decays into a pointer, which gets passed to the function and used to influence the variables in the outer scope?
Bonus question: If this is true, does that mean I should consider caching referenced parameters inside of function bodies, so that I avoid the hidden dereferences that come with passing these references? I would then conservatively access the actual reference parameters, only when I need to actually write something to them. Is this approach warranted or is it best to trust the compiler to cache the values for me if it deems the cost of dereferencing higher than the cost of copying them one time?
Code for bonus question:
void sum(int& a, const int& b) {
int aCached = a;
// Do processing that required reading from a with aCached.
// Do processing the requires writing to a with the a reference.
a += b;
}
Bonus bonus question: Is it safe to assume (assuming everything above is true), that, when "const int& b" is passed, the compiler will be smart enough to pass b by value when passing by pointer isn't efficient enough? My reasoning behind this is that values are ok for "const int& b" because you never try to write to it, only read.
The compiler can decide to implement references as pointers, or inlining or any other method it chooses to use. In terms of performance, it's irrelevant. The compiler can and will do whatever it wants to when it comes to optimization. The compiler can implement your reference as a pass-by-value if it wants to (and if it's valid to do so in the specific situation).
Caching the result won't help because the compiler will do that anyways.
If you want to explicitly tell the compiler that the value might change (because of another thread that has access to the same pointer), you need to use the keyword volatile (or std::atomic if you're not already using a std::mutex).
Edit: The keyword "volatile" is never required for multithreading. std::mutex is enough.
If you don't use the keyword volatile, the compiler will almost certainly cache the result for you (if appropriate).
There are, however, at least 2 actual differences in the rules between pointers and references.
Taking the address (pointer) of a temporary value (rvalue) is undefined behavior in C++.
References are immutable, sometimes need to be wrapped in std::ref.
Here I'll provide examples for both differences.
This code using references is valid:
static int do_stuff(const int& i)
{
}
int main()
{
do_stuff(5);
return 0;
}
But this code has undefined behavior (in practice it will probably still work):
static int do_stuff(const int* i)
{
}
int main()
{
do_stuff(&5);
return 0;
}
That's because taking the address of a temporary value (non lvalue) is undefined behavior in C++. The value is not guaranteed to have an address. Note that taking the address like this is valid:
static int do_stuff(const int& i)
{
const int *ptr = &i;
}
int main()
{
do_stuff(5);
return 0;
}
Because inside of the function do_stuff, the variable has a name and is therefore an lvalue. That means that by the time it's inside of do_stuff it's guaranteed to have an address.
So that's one difference between a pointer an a reference in C++.
There is another difference, and that is the constness / immutability.
On important thing to know about in C++ is the use for the helper function std::ref.
Consider the following code:
#include <functional>
#include <thread>
#include <future>
#include <chrono>
#include <iostream>
struct important_t
{
int val = 0;
};
static void work(const volatile important_t& arg)
{
std::cout << "Doing work..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
}
int main()
{
important_t my_object;
{
std::cout << "Starting thread" << std::endl;
std::future<void> t = std::async(std::launch::async, work, std::ref(my_object));
std::cout << "Waiting for thread to finish" << std::endl;
}
return 0;
}
The above code will compile just fine, and is perfectly valid C++ code.
But if you wrote it like this:
std::future<void> t = std::async(std::launch::async, work, my_object);
It wouldn't compile. That's because of the std::ref.
The reason that the code doesn't compile without std::ref is that the function std::async (and also std::thread) requires each and every one of the objects being passed as function parameters to be copy constructible.
That demonstrates a fundamental difference between references and all other built-in types in C++. References are immutable, and there's no way to make them editable.
Consider the following code:
#include <iostream>
int main()
{
// Perfectly valid
// Prints 5
{
int val = 0;
int& val_ref = val;
val_ref = 5;
std::cout << val << std::endl;
}
// Compiler error:
// A reference must always be initialized.
// A reference will always point to the same value throughout its lifetime.
{
int val = 0;
int& val_ref;
val_ref = val;
val_ref = 5;
std::cout << val << std::endl;
}
// We will encounter a similar compiler error with a const pointer:
// A const value must always be initialized.
// A const pointer will always point to the same value throughout its lifetime.
{
int val = 0;
int *const val_ptr;
val_ref = &val;
val_ref = 5;
std::cout << val << std::endl;
}
return 0;
}
That leads to the conclusion that a reference is not the same thing as a pointer in C++. It's almost the same thing as a const pointer.
Just a little bit of clarification:
A const pointer to a const int:
void do_stuff(const int *const val)
{
int i;
val = 5; // Error
val = &i; // Error
}
A const pointer to an int:
void do_stuff(int *const val)
{
int i;
val = 5; // Allowed. The int is not const.
val = &i; // Error
}
A pointer to a const int:
void do_stuff(const int* val)
{
int i;
val = 5; // Error
val = &i; // Allowed
}
An int reference in C++ is the closest thing to a const pointer to an int. The int is editable, the pointer is not.

Reference from literal

I am calling a function with the signature
void setValue(int& data)
I would like to pass a literal number to it:
setValue(1);
But I get:
error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
Is there a way I can make this work without changing the function (it's in a library) and without assigning each literal value to a variable?
Assuming setValue does not actually modify its argument and just has a wrong signature which you cannot change, here is an approach which is not thread-safe among other things:
#include <iostream>
void setValue(int &i)
{
std::cout << "i = " << i << std::endl;
}
int& evil(int i)
{
static int j;
j = i;
return j;
}
int main()
{
setValue(evil(1));
setValue(evil(2));
}
When you declare the argument as being an int&, you are saying that the function called can change the value and the caller will see the change.
So it is no longer valid to pass a literal value then because how could the function possibly change the given value of a literal?
If you don't want the setValue to be able to change the given value, make the argument either be an int or const int&. And if you do want the setValue function to be able to change the value, then the caller must declare a non-const variable to hold the int and pass in that.
Can I change something at the call site to make it work
The problem with your code is that you declared your function to expect a reference, which means the compiler has to prepare the code to allow the function to change whatever you pass into it at the call site. So yes, sure, you can declare a variable, set it to 1 and call your function with it.
Contrast this with a constant reference in the declaration, where the compiler knows you won't change it inside the function, and then you can pass a literal in without issues. In fact, any logical, thought out design will make setters accept constant parameters because it won't change them, it will just store a possibly processed value in its state.
The answer to „what do I do if a library has a bad interface and I can't change it“ is usually „write a wrapper“. Assuming this is a method of some class BadLibraryClass, you could do something like:
class Wrapper {
public:
BadLibraryClass inner;
setValue(int i) {
inner.setValue(i); // i is an lvalue
}
};
This is just a crude example. Perhaps inner is better off being a pointer, a reference or even a smart pointer. Perhaps you want a conversion operator to BadLibraryClass. Perhaps you can use inheritance to expose other methods of BadLibraryClass.
Two options:
Use the result of assignment:
static int _data;
void myCall() {
setValue((_data = 3));
}
Write a wrapper:
struct setValueW {
int _data;
// constructor
setValueW(int _data) : _data(_data) {
setValue(_data);
}
// if you want to call it again
void operator()() {
setValue(_data);
}
};
void myCall2() {
setValueW(3);
}
AFAIK, references keeps the addresses of the variable. 1 is not variable. It is temporary.
Take a look this article(this is a quote from this site)
c++11 introduced a new kind of reference variable -- an r-value reference
To declare one, use && after a type
int & // type designation for an L-value reference
int && // type designation for an R-value reference
L-value references can only refer to L-values
R-value references can reference to R-values (temporaries)
int x, y, z; // regular variables
int & r = x; // L-value reference to the variable x
int & r2 = x + y; // This would be ILLEGAL, since x + y is an R-value
int && r3 = x + y; // LEGAL. R-value reference, referring to R-value
So you can use (But this is not useful. It may be more useful if you write this in plain without rvalue or lvalue.):
void setValue(int&& data)
setValue(1);
Or you can use that:
void setValue(int& data)
int a = 11;
setValue(a);
Don't forget for second example. If you change the value of data parameter. You will have change the a variable value.
No, you can't.
An lvalue reference like that binds to a variable (roughly speaking).
Your literal is not such a thing. It never had a name, and may not even have a home in memory.
Your two options are the two things you ruled out, I'm afraid.
For what it's worth, this is not your fault: that is a rather poor setter. It should take const int& (which will automatically create a nice temporary variable for you out of the literal!), or even just const int.

Why cannot assign value to non-const reference?

Why these definitions are all ok:
int func(int p=255) {
return p;
}
int func1(const int &p=255) {
return p;
}
but this definition:
int func2(int &p=255) {
return p;
}
leads to compile error ?
What is the logic behind it ?
Taking arguments by reference means, you dont work with your local copy of the variable, but with a variable already defined in the scope of the calling function.
While your first example makes sense (you have a local variable p that you can fill with a default value) the second example is a bit more tricky: Usually when using references you expect the variable to have an address, since you want to modify it. For const-refernces, the compiler will still allow you to pass a literal, even if something like "reference to a literal" makes no sense at all.
In the third case the compiler expects you to modify p. But what part of the memory should this modification affect? "255" has no address - therefore it cant be used as a reference.
If you want to have a more detailed explanation, you should probably look for keywords like "rvalue" and "lvalue".
The attempted function definition
auto func2( int& p = 255 )
-> int
{ return p; }
… fails because you can't bind an rvalue to a reference to non-const. Basically that rule is because a simple value like 255 isn't modifiable. While the reference can be used to modify.
One simple solution is to express the default as a separate overload:
auto func2( int& p )
-> int
{ return p; }
auto func2()
-> int
{
int scratchpad = 255;
return func2( scratchpad );
}
A non-const reference must be bound to lvalue (i.e. its address could be got). 255 (i.e. an int literal) is not a lvalue, so int &p=255 fails.
A const reference could be bound to rvalue, and for this case, a temporary int will be created and initialized from 255. The temporary int's lifetime will be the same as the const reference.
int func(int p=255) {
return p;
}
p here is copied by value, and it is defined to exist in the scope of func.
int func2(int &p) {
return p;
}
// e.g. use:
int value = 10;
func2(value); // func2 *could* modify value because it is passed by non-const reference
In this case the compiler here expects p to have a name somewhere in memory (i.e. lvalue), so it can possibly write to it within func2. Passing by non-const reference allows you to modify the variable used in the function call. Since p must belong to someone else somewhere since it can be modified, you can't assign a default value to it.
But what about the const-reference case? Here, the compiler is smart enough to know that p can never be written to since it is const, so it doesn't need to have a name in memory to write to. In cases of a literal being passed (e.g. 255), it (behind the scenes) essentially creates a temporary and passes that temporary variable to the function.
int func1(const int &p=255) {
return p;
}
func1(10);
// Behind the scenes, the compiler creates something along these lines
// since it can never be modified.
const int some_temporary = 10;
func1(some_temporary);

Difference of function argument as (const int &) and (int & a) in C++

I know that if you write void function_name(int& a), then function will not do local copy of your variable passed as argument. Also have met in literature that you should write void function_name(const int & a) in order to say compiler, that I dont want the variable passed as argument to be copied.
So my question: what is the difference with this two cases (except that "const" ensures that the variable passed will not be changed by function!!!)???
You should use const in the signature whenever you do not need to write. Adding const to the signature has two effects: it tells the compiler that you want it to check and guarantee that you do not change that argument inside your function. The second effect is that enables external code to use your function passing objects that are themselves constant (and temporaries), enabling more uses of the same function.
At the same time, the const keyword is an important part of the documentation of your function/method: the function signature is explicitly saying what you intend to do with the argument, and whether it is safe to pass an object that is part of another object's invariants into your function: you are being explicit in that you will not mess with their object.
Using const forces a more strict set of requirements in your code (the function): you cannot modify the object, but at the same time is less restrictive in your callers, making your code more reusable.
void printr( int & i ) { std::cout << i << std::endl; }
void printcr( const int & i ) { std::cout << i << std::endl; }
int main() {
int x = 10;
const int y = 15;
printr( x );
//printr( y ); // passing y as non-const reference discards qualifiers
//printr( 5 ); // cannot bind a non-const reference to a temporary
printcr( x ); printcr( y ); printcr( 5 ); // all valid
}
So my question: what is the difference
with this two cases (except that
"const" enshures that the variable
passes will not be changed by
function!!!)???
That is the difference.
You state the difference right. You may also formulate it as:
If you want to specify that the function may change the argument (i.e. for init_to_big_number( int& i ) by specifying the argument by (variable) reference. When in doubt, specify it const.
Note that the benefit of not copying the argument is in performance, i.e. for 'expensive' objects. For built-in types like int it makes no sense to write void f( const int& i ). Passing the reference to the variable is just as expensive as passing the value.
There is a big difference in terms of parameter they could operate on,
Say you have a copy constructor for your class from int,
customeclass(const int & count){
//this constructor is able to create a class from 5,
//I mean from RValue as well as from LValue
}
customeclass( int & count){
//this constructor is not able to create a class from 5,
//I mean only from LValue
}
The const version can essentially operate on temporary values and non constant version could not operate on temporary, you would easily face issue when you miss out const where it is needed and use STL, but you get weired error telling it could not find the version that takes temporary. I recommend use const where ever you can.
They are used for different purposes. Passing a variable using const int& ensures you get the pass-by-copy semantics with much better performance. You are guaranteed that the called function (unless it does some crazy things using const_cast) will not modify your passed argument without creating a copy. int& is used when there are generally multiple return values from a function. In that case these can be used hold the results of the function.
I would say that
void cfunction_name(const X& a);
allows me to pass a reference to temporary object as follows
X make_X();
function_name(make_X());
While
void function_name(X& a);
fails to achieve this. with the following error
error: invalid initialization of non-const reference of type 'X&' from a temporary of type 'X'
leaving out the performance discussion, let the code speak!
void foo(){
const int i1 = 0;
int i2 = 0;
i1 = 123; //i gets red -> expression must be a modifiyble value
i2 = 123;
}
//the following two functions are OK
void foo( int i ) {
i = 123;
}
void foo( int & i ) {
i = 123;
}
//in the following two functions i gets red
//already your IDE (VS) knows that i should not be changed
//and it forces you not to assign a value to i
//more over you can change the constness of one variable, in different functions
//in the function where i is defined it could be a variable
//in another function it could be constant
void foo( const int i ) {
i = 123;
}
void foo( const int & i ) {
i = 123;
}
using "const" where it is needed has the following benefits:
* you can change the constness of one variable i, in different functions
in the function where i is defined it could be a variable
in another function it could be constant value.
* already your IDE knows that i should not be changed.
and it forces you not to assign a value to i
regards
Oops

What does '&' do in a C++ declaration?

I am a C guy and I'm trying to understand some C++ code. I have the following function declaration:
int foo(const string &myname) {
cout << "called foo for: " << myname << endl;
return 0;
}
How does the function signature differ from the equivalent C:
int foo(const char *myname)
Is there a difference between using string *myname vs string &myname? What is the difference between & in C++ and * in C to indicate pointers?
Similarly:
const string &GetMethodName() { ... }
What is the & doing here? Is there some website that explains how & is used differently in C vs C++?
The "&" denotes a reference instead of a pointer to an object (In your case a constant reference).
The advantage of having a function such as
foo(string const& myname)
over
foo(string const* myname)
is that in the former case you are guaranteed that myname is non-null, since C++ does not allow NULL references. Since you are passing by reference, the object is not copied, just like if you were passing a pointer.
Your second example:
const string &GetMethodName() { ... }
Would allow you to return a constant reference to, for example, a member variable. This is useful if you do not wish a copy to be returned, and again be guaranteed that the value returned is non-null. As an example, the following allows you direct, read-only access:
class A
{
public:
int bar() const {return someValue;}
//Big, expensive to copy class
}
class B
{
public:
A const& getA() { return mA;}
private:
A mA;
}
void someFunction()
{
B b = B();
//Access A, ability to call const functions on A
//No need to check for null, since reference is guaranteed to be valid.
int value = b.getA().bar();
}
You have to of course be careful to not return invalid references.
Compilers will happily compile the following (depending on your warning level and how you treat warnings)
int const& foo()
{
int a;
//This is very bad, returning reference to something on the stack. This will
//crash at runtime.
return a;
}
Basically, it is your responsibility to ensure that whatever you are returning a reference to is actually valid.
Here, & is not used as an operator. As part of function or variable declarations, & denotes a reference. The C++ FAQ Lite has a pretty nifty chapter on references.
string * and string& differ in a couple of ways. First of all, the pointer points to the address location of the data. The reference points to the data. If you had the following function:
int foo(string *param1);
You would have to check in the function declaration to make sure that param1 pointed to a valid location. Comparatively:
int foo(string &param1);
Here, it is the caller's responsibility to make sure the pointed to data is valid. You can't pass a "NULL" value, for example, int he second function above.
With regards to your second question, about the method return values being a reference, consider the following three functions:
string &foo();
string *foo();
string foo();
In the first case, you would be returning a reference to the data. If your function declaration looked like this:
string &foo()
{
string localString = "Hello!";
return localString;
}
You would probably get some compiler errors, since you are returning a reference to a string that was initialized in the stack for that function. On the function return, that data location is no longer valid. Typically, you would want to return a reference to a class member or something like that.
The second function above returns a pointer in actual memory, so it would stay the same. You would have to check for NULL-pointers, though.
Finally, in the third case, the data returned would be copied into the return value for the caller. So if your function was like this:
string foo()
{
string localString = "Hello!";
return localString;
}
You'd be okay, since the string "Hello" would be copied into the return value for that function, accessible in the caller's memory space.
Your function declares a constant reference to a string:
int foo(const string &myname) {
cout << "called foo for: " << myname << endl;
return 0;
}
A reference has some special properties, which make it a safer alternative to pointers in many ways:
it can never be NULL
it must always be initialised
it cannot be changed to refer to a different variable once set
it can be used in exactly the same way as the variable to which it refers (which means you do not need to deference it like a pointer)
How does the function signature differ from the equivalent C:
int foo(const char *myname)
There are several differences, since the first refers directly to an object, while const char* must be dereferenced to point to the data.
Is there a difference between using string *myname vs string &myname?
The main difference when dealing with parameters is that you do not need to dereference &myname. A simpler example is:
int add_ptr(int *x, int* y)
{
return *x + *y;
}
int add_ref(int &x, int &y)
{
return x + y;
}
which do exactly the same thing. The only difference in this case is that you do not need to dereference x and y as they refer directly to the variables passed in.
const string &GetMethodName() { ... }
What is the & doing here? Is there some website that explains how & is used differently in C vs C++?
This returns a constant reference to a string. So the caller gets to access the returned variable directly, but only in a read-only sense. This is sometimes used to return string data members without allocating extra memory.
There are some subtleties with references - have a look at the C++ FAQ on References for some more details.
#include<iostream>
using namespace std;
int add(int &number);
int main ()
{
int number;
int result;
number=5;
cout << "The value of the variable number before calling the function : " << number << endl;
result=add(&number);
cout << "The value of the variable number after the function is returned : " << number << endl;
cout << "The value of result : " << result << endl;
return(0);
}
int add(int &p)
{
*p=*p+100;
return(*p);
}
This is invalid code on several counts. Running it through g++ gives:
crap.cpp: In function ‘int main()’:
crap.cpp:11: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int*’
crap.cpp:3: error: in passing argument 1 of ‘int add(int&)’
crap.cpp: In function ‘int add(int&)’:
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:20: error: invalid type argument of ‘unary *’
A valid version of the code reads:
#include<iostream>
using namespace std;
int add(int &number);
int main ()
{
int number;
int result;
number=5;
cout << "The value of the variable number before calling the function : " << number << endl;
result=add(number);
cout << "The value of the variable number after the function is returned : " << number << endl;
cout << "The value of result : " << result << endl;
return(0);
}
int add(int &p)
{
p=p+100;
return p;
}
What is happening here is that you are passing a variable "as is" to your function. This is roughly equivalent to:
int add(int *p)
{
*p=*p+100;
return *p;
}
However, passing a reference to a function ensures that you cannot do things like pointer arithmetic with the reference. For example:
int add(int &p)
{
*p=*p+100;
return p;
}
is invalid.
If you must use a pointer to a reference, that has to be done explicitly:
int add(int &p)
{
int* i = &p;
i=i+100L;
return *i;
}
Which on a test run gives (as expected) junk output:
The value of the variable number before calling the function : 5
The value of the variable number after the function is returned : 5
The value of result : 1399090792
One way to look at the & (reference) operator in c++ is that is merely a syntactic sugar to a pointer. For example, the following are roughly equivalent:
void foo(int &x)
{
x = x + 1;
}
void foo(int *x)
{
*x = *x + 1;
}
The more useful is when you're dealing with a class, so that your methods turn from x->bar() to x.bar().
The reason I said roughly is that using references imposes additional compile-time restrictions on what you can do with the reference, in order to protect you from some of the problems caused when dealing with pointers. For instance, you can't accidentally change the pointer, or use the pointer in any way other than to reference the singular object you've been passed.
In this context & is causing the function to take stringname by reference.
The difference between references and pointers is:
When you take a reference to a variable, that reference is the variable you referenced. You don't need to dereference it or anything, working with the reference is sematically equal to working with the referenced variable itself.
NULL is not a valid value to a reference and will result in a compiler error. So generally, if you want to use an output parameter (or a pointer/reference in general) in a C++ function, and passing a null value to that parameter should be allowed, then use a pointer (or smart pointer, preferably). If passing a null value makes no sense for that function, use a reference.
You cannot 're-seat' a reference. While the value of a pointer can be changed to point at something else, a reference has no similar functionality. Once you take a variable by reference, you are effectively dealing with that variable directly. Just like you can't change the value of a by writing b = 4;. A reference's value is the value of whatever it referenced.