I was told to change all pass by value or pass by reference arguments in a Qt/C++ application to pass by const reference. All Qt types (QString for instance) are concerned, but not native types (double, integer). Could you explain more precisely why, or point to reference?
Pass by value makes a local copy of the argument, so if a big structure is passed there might be quite a big loss of time and space. That's why big structures shall be passed by reference. But if the function/method really needs the copy of the parameter, then pass it by value.
On the other hand passing by reference makes the object vulnerable to changes - if the state of the object is changed in the function, the original object is modified since they are the same. That's why const reference is used: it prevents from changing/editing the object by mistake.
Another reason is polymorphism. When passing by value virtuality is lost, while passing by reference or pointer virtual methods work as expected.
When passing by reference we are passing the address of the same instance where pass by value involves copying of the object to another (via a copy constructor in case of QString) native types like int, double etc will be smaller in size so there is less overhead comparing QString like objects. By passing a const reference we ensure that the object will not get modified in the passed function as the changes made by the called function affects the object passed as both points to the same location.
Related
In what circumstances should I prefer pass-by-reference? Pass-by-value?
There are four main cases where you should use pass-by-reference over pass-by-value:
If you are calling a function that needs to modify its arguments, use pass-by-reference or pass-by-pointer. Otherwise, you’ll get a copy of the argument.
If you're calling a function that needs to take a large object as a parameter, pass it by const reference to avoid making an unnecessary copy of that object and taking a large efficiency hit.
If you're writing a copy or move constructor which by definition must take a reference, use pass by reference.
If you're writing a function that wants to operate on a polymorphic class, use pass by reference or pass by pointer to avoid slicing.
There are several considerations, including:
Performance
Passing by value copies the data, so passing large data structures by value can inhibit performance. Passing by reference passes only a reference (basically the address) to the data. For large data structures, this can greatly improve performance. For smaller data structures (like an int), passing by reference can inhibit performance.
Modifications
Passing by value copies the data so if the target code modifies that copy, it will not affect the original. Passing by reference passes only the address of the data, so modifications made against that reference will be "visible" to the calling code.
Yes.
Pass by value for things like native types that are small enough that passing them directly is efficient. Otherwise use pass by (const) reference.
The hard part is writing a template that could apply to either (in which case, you usually want to use pass by reference -- the potential penalty for passing a large object by value is much worse than the potential penalty for passing by reference when passing by value would have been preferred).
Edit: this, of course, is assuming a situation where the required semantics would allow either one -- obviously if you're working with something like polymorphic objects, there's no real "preference" involved, because you must use a pointer or reference to get correct behavior.
As others already have replied to your question sufficiently well, I would like to add an important point:
If the class does not have public copy-constructor, then you don't have choice to pass by value; you have to pass by reference (or you can pass pointer).
The following program would not compile:
class A
{
public:
A(){}
private:
A(const A&) {}
};
//source of error : pass by value
void f(A ) {}
int main() {
A a;
f(a);
return 0;
}
Error:
prog.cpp: In function ‘int main()’:
prog.cpp:10: error: ‘A::A(const A&)’ is private
prog.cpp:18: error: within this context
prog.cpp:18: error: initializing argument 1 of ‘void f(A)’
See yourself at ideone : http://www.ideone.com/b2WLi
But once you make function f pass by reference, then it compiles fine : http://www.ideone.com/i6XXB
here's the simple rule:
pass by reference when the value is large.
the other answers are amazing. Just trying to make this simplest.
You have tagged your question with both C and C++.
Therefore, I suggest that you consider using pass by reference in C++ which supports this feature and that you do not consider using it in C which does not support this feature.
pass by reference can be called only in below conditions:
Pass-by-references is more efficient than pass-by-value, because it does not copy the arguments. The formal parameter is an alias for the argument. When the called function read or write the formal parameter, it is actually read or write the argument itself.
The difference between pass-by-reference and pass-by-value is that modifications made to arguments passed in by reference in the called function have effect in the calling function, whereas modifications made to arguments passed in by value in the called function can not affect the calling function.
Use pass-by-reference if you want to modify the argument value in the calling function. Otherwise, use pass-by-value to pass arguments.
The difference between pass-by-reference and pass-by-pointer is
that pointers can be NULL or reassigned whereas references cannot.
Use pass-by-pointer if NULL is a valid parameter value or if you want to reassign the pointer.
Otherwise, use constant or non-constant references to pass arguments.
While pointers are references, "reference" in c++ usually refers to the practice of tagging a parameter of SomeType&.
Which you should never do. The only place it is appropriate is as a magic syntax required to implement the various pre-defined operators. Otherwise:
You should never pass out parameters by reference - pass by pointer, otherwise you make code reviews all but impossible. Pass by reference makes it impossible to tell by examining a call which parameters can be expected to be changed.
You should never pass in parameter by reference either. Again, this means you are performing a meta optimization. You should always just pass-by-value, otherwise you are guilty of peeking inside an object, examining its implementation and deciding that pass-by-reference is preferred for some reason.
Any c++ class should implement all the copy and assignment constructors and overloads necessary to be passed around by value. Otherwise it has not done its job, of abstracting the programmer from the implementation details of the class.
I'd like to work out conventions on passing parameters to functions/methods. I know it's a common issue and it has been answered many times, but I searched a lot and found nothing that fully satisfies me.
Passing by value is obvious and I won't mention this. What I came up with is:
Passing by non-const reference means, that object is MODIFIED
Passing by const reference means, that object is USED
Passing by pointer means, that a reference to object is going to be STORED. Whether ownership is passed or not will depend on the context.
It seems to be consistent, but when I want to pick heap-allocated object and pass it to 2. case parameter, it'd look like this:
void use(const Object &object) { ... }
//...
Object *obj = getOrCreateObject();
use(*obj);
or
Object &obj = *getOrCreateObject();
use(obj);
Both look weird to me. What would you advise?
PS I know that one should avoid raw pointers and use smart instead (easier memory managment and expressiveness in ownership) and it can be the next step in refactoring the project I work on.
You can use these conventions if you like. But keep in mind that you cannot assume conventions when dealing with code written by other people. You also cannot assume that people reading your code are aware of your conventions. You should document an interface with comments when it might be ambiguous.
Passing by pointer means, that object is going to be STORED. Who's its owner will depend on the context.
I can think of only one context where the ownership of a pointer argument should transfer to the callee: Constructor of a smart pointer.
Besides possible intention of storing, a pointer argument can alternatively have the same meaning as a reference argument, with the addition that the argument is optional. You typically cannot represent an optional argument with a reference since they cannot be null - although with custom types you could use a reference to a sentinel value.
Both look weird to me. What would you advise?
Neither look weird to me, so my advise is to get accustomed.
The main problem with your conventions is that you make no allowance for the possibility of interfacing to code (e.g. written by someone else) that doesn't follow your conventions.
Generally speaking, I use a different set of conventions, and rarely find a need to work around them. (The main exception will be if there is a need to use a pointer to a pointer, but I rarely need to do that directly).
Passing by non-const reference is appropriate if ANY of the following MAY be true;
The object may be changed;
The object may be passed to another function by a non-const reference [relevant when using third party code by developers who choose to omit the const - which is actually something a lot of beginners or lazy developers do];
The object may be passed to another function by a non-const pointer [relevant when using third party code be developers who choose to omit the const, or when using legacy APIs];
Non-const member functions of the object are called (regardless of whether they change the object or not) [also often a consideration when using third-party code by developers who prefer to avoid using const].
Conversely, const references may be passed if ALL of the following are true;
No non-mutable members of the object are changed;
The object is only passed to other functions by const reference, by const pointer, or by value;
Only const member functions of the object are called (even if those members are able to change mutable members.
I'll pass by value instead of by const reference in cases where the function would copy the object anyway. (e.g. I won't pass by const reference, and then construct a copy of the passed object within the function).
Passing non-const pointers is relevant if it is appropriate to pass a non-const reference but there is also a possibility of passing no object (e.g. a nullptr).
Passing const pointers is relevant if it is appropriate to pass a const reference but there is also a possibility of passing no object (e.g. a nullptr).
I would not change the convention for either of the following
Storing a reference or pointer to the object within the function for later use - it is possible to convert a pointer to a reference or vice versa. And either one can be stored (a pointer can be assigned, a reference can be used to construct an object);
Distinguishing between dynamically allocated and other objects - since I mostly either avoid using dynamic memory allocation at all (e.g. use standard containers, and pass them around by reference or simply pass iterators from them around) or - if I must use a new expression directly - store the pointer in another object that becomes responsible for deallocation (e.g. a std::smart_pointer) and then pass the containing object around.
In my opionion, they are the same. In the first part of your post, you are talking about the signature, but your example is about function call.
Q: Is pass-by-value/reference defined strictly by behavior or implementation wise in C++, and can you provide an authoritative citation?
I had a conversion with a friend about pass-by-value/reference in C++. We came to a disagreement on the definition of pass-by-value/reference. I understand that passing a pointer to a function is still pass-by-value since the value of the pointer is copied, and this copy is used in the function. Subsequently, dereferencing the pointer in the function and mutating it will modify the original variable. This is where the disagreement appears.
His stance: Just because a pointer value was copied and passed to the function, performing operations on the dereferenced pointer has the ability to affect the original variable, so it has the behavior of pass-by-reference, passing a pointer to a function.
My stance: Passing a pointer to a function does copy the value of the pointer, and operations in the function may affect the original variable; however, just because it may affect the original, this behavior does not constitute it to be pass-by-reference since it is the implementation of the language that is what defines these terms, pass-by-value/reference.
Quoting from the definition given by the highest voted answer here: Language Agnostic
Pass by Reference
When a parameter is passed by reference, the caller and the callee use the same variable for the parameter. If the callee modifies the parameter variable, the effect is visible to the caller's variable.
Pass by Value
When a parameter is passed by value, the caller and callee have two independent variables with the same value. If the callee modifies the parameter variable, the effect is not visible to the caller.
I still have an ambiguous feeling after reading these. For example, the pass by value/reference quotes can support either of our claims. Can anyone clear up the definitions of whether these definition stem from behavior or implementation and provide a citation? Thanks!
Edit: I should be a little more careful of my vocabulary. Let me extend my question with a clarification. What I mean when questioning pass-by-reference is not talking purely about the C++ implementation of & reference, but instead also the theory. In C++, is it that the & pass-by-reference is true PBR because not only can it modify the original value, but also the memory address of the value. This leads to this, example with pointers also count as PBR?
void foo(int ** bar){
*bar = *bar+(sizeof(int*));
cout<<"Inside:"<<*bar<<endl;
}
int main(){
int a = 42;
int* ptrA = &a;
cout<<"Before"<<ptrA<<endl;
foo(&ptrA);
cout<<"After:"<<ptrA<<endl;
}
The output would be that After ptrA is equal to Inside, meaning that not only can the function modify a, but ptrA. Because of this, does this define call-by-reference as a theory: being able to not only modify the value, but the memory address of the value. Sorry for the convoluted example.
You talk a lot about pointers here, which they are indeed passed by value most of the time, but you don't mention actual C++ references, which are actual references.
int a{};
int& b = a;
// Prints true
std::cout << std::boolalpha << (&b == &a) << std::endl;
Here, as you can see, both variables have the same address. Put it simply, especially in this case, references act as being another name for a variable.
References in C++ are special. They are not objects, unlike pointers. You cannot have an array of references, because it would require that references has a size. Reference are not required to have a storage at all.
What about actually passing a variable by reference then?
Take a look at this code:
void foo(int& i) {
i++;
}
int main() {
int i{};
foo(i);
// prints 1
std::cout << i << std::endl;
}
In that particular case, the compiler must have a way to send to which variable the reference is bound. Indeed references are not required to have any storage, but they are not required to not have one either. In this case, if optimizations are disabled, it is most likely that the compiler implements the behavior of references using pointers.
Of course, if optimizations are enabled, it may skip the passing and completely inline the function. In that case, the reference don't exist, or don't have any storage, because the original variable will be used directly.
Other similar optimization happens with pointers too, but that's not the point: The point is, the way references are implemented is implementation defined. They are most likely implemented in term of pointers, but they are not forced to, and the way a reference is implemented may vary from case to case. The behavior of references are defined by the standard, and really is pass-by-reference.
What about pointers? Do they count as passing by reference?
I would say no. Pointers are objects, just like int, or std::string. You can even pass a reference to a pointer, allowing you to change the original pointer.
However, pointers do have reference semantics. They are not reference indeed, just like std::reference_wrapper is not a reference either, but they have reference semantics. I wouldn't call passing a pointer "passing by reference", because you don't have an actual reference, but you indeed have reference semantics.
A lot of things have reference semantics, pointers, std::reference_wrapper, a handle to a resource, even GLuint, which are handle to an opengl object, all have reference semantics, but they are not references. You don't have a reference to the actual object, but you can change the pointed-to object through these handles.
There are other good articles and answers you can read about. They are all very informative about value and reference semantics.
isocpp.org: Reference and Value Semantics
Andrzej's C++ blog: Value semantics
Stack Overflow: What are the differences between a pointer variable and a reference variable in C++?
Passing by value/reference (you forgot one which is passing the address to the location in memory by using a pointer) is part of the implementation of C++.
There is one more way to pass variables to functions, and that is by address. Passing an argument by address involves passing the address of the argument variable (using a pointer) rather than the argument variable itself. Because the argument is an address, the function parameter must be a pointer. The function can then dereference the pointer to access or change the value being pointed to.
Take a look here at what I have always thought to be an authoritative Source: Passing Arguments by Address.
You're correct in regards to a value being copied when passing by value. This is the default behavior in C++. The advantage of passing by value into a function is that the original value cannot be changed by the function when the value is passed into it and this prevents any unwanted bugs and/or side effects when changing the value of an argument.
The problem with passing by Value is that you will incur a huge performance penalty if you pass an entire struct or class many times into your function as you will be passing entire copies of the value you are trying to pass AND in the case of a mutator method in a class, you will not be able to change the original values and will therefore end up creating multiple copies of the data you are trying to modify because you will be forced to return the new value from the function itself instead of from the location in memory where the data structure resides. This is just completely inefficient.
You only want to pass by value when you don't have to change the value of the argument.
Here is a good source on the topic of Passing Arguments by Value.
Now, you will want to use the "Pass by Reference" behavior when you do need to change the value of an argument in the case of arrays, Classes, or structs. It is more efficient to change the value of a data structure by Passing a Reference to the location in memory where the data structure resides into the function. This has the benefit that you will not have to return the new value from the function but rather, the function can then change the value of the reference you have given it directly where it resides in memory.
Take a look here to read more about about Passing an Argument by Reference.
EDIT: In regards to the issue as to whether or not you are passing a non-const by reference or by value when using a pointer, it seems to me the answer is clear. When using a pointer to a non-const, it is neither. When passing a pointer as an argument to a function, you in fact are "Passing the Value" of the ADDRESS into the function and since it is a copy of the ADDRESS of the location in memory where the non-const resides, then you are able to change the Value of the data at that location and not the value of the pointer itself. If you do not want to change the value of the data located at the address pointed to by the pointer being passed by value as an argument into your function, it is good form to make the pointer to an argument a const since the function will not be changing the value of the data itself.
Hope that makes sense.
References are different from pointers. The main reason references were introduced is to support Operator Overloading. C++ is derived from C and during the process, Pointers were inherited from C. As Stroustrup says:
C++ inherited pointers from C, so I couldn't remove them without causing serious compatibility problems.
So, effectively there are three different ways of parameters passing:
Pass by value
Pass by reference &
Pass by pointers.
Now, pass by pointer has the same effect as pass by reference. So how to decide on what you want to use? Going back to what Stroustrup said:
That depends on what you are trying to achieve:
If you want to change the object passed, call by reference or use a pointer; e.g. void f(X&); or void f(X*);
If you don't want to change the object passed and it is big, call by const reference; e.g. void f(const X&);
Otherwise, call by value; e.g. void f(X);
Ref: http://www.stroustrup.com/bs_faq2.html#pointers-and-references
Those terms are about the variable that is passed, in this case the pointer. If you pass a pointer to a function then the variable that is passed is the pointer - holding the address of the object - to an object and not the object it points to.
If you pass a pointer by value then chaning the object it is pointing to in the function would not affect the pointer that was passed to the function.
If you pass the pointer by reference then you can change in the function where the pointer is pointing to and it would modifiy the pointer that was passed to this function.
Thats how it is defined. Otherwise you could argue that if you have a global std::map<int,SomeObject> and you pass an int as key to the object, would also be a pass by reference because you can modify the objects in that global map, and the caller would see those changes. Because this int is also just a pointer to an object.
This question already has answers here:
Is it better in C++ to pass by value or pass by reference-to-const?
(11 answers)
Closed 9 years ago.
I am always in a doubt on when I should reference and when I should use a variable pass.
For example, one of the API is called by the JOBJECTs -
QLIST retrive_cinemas(QString& options)
{
return (staticobject::getcinemas(options));
}
or
QLIST retrive_cinemas(QString options)
{
return (staticobject::getcinemas(options));
}
It seems to me that your problem can be reduced to something like this:
You have a function/method f(), and a class X, and you want to
know if/when X should be passed to f() by reference or not.
You can identify three options:
void f(X v) // #1 - pass by value
void f(const X& cr) // #2 - pass by const reference (&)
void f(X& r) // #3 - pass by reference (&)
If X is cheap to copy (e.g. it's an int, a double, etc.),
and you do not want to modify it, then pass by value (#1).
If X is not cheap to copy (e.g. it's a vector, a string,
etc.), and yo do not want to modify it, then pass by const
reference (#2).
If you want to modify the argument of type X inside f(), then
pass by reference.
In the particular code you posted, since QString is a full-fledged class which is not cheap to copy as e.g. an int or a double (even if it uses COW techniques and "implicit sharing", I believe that copying still implies a call to something like Win32 InterlockedIncrement() for increasing the ref count in a thread-safe atomic way), I'd pass it by const reference (i.e. const QString &, #2) if you do not want to modify it inside the function.
Just pass by reference (QString&, #3) if you want to modify it inside the function's body.
In Qt the answer depends on whether the object you would like to pass uses implicit sharing or not:
Many C++ classes in Qt use implicit data sharing to maximize resource
usage and minimize copying. Implicitly shared classes are both safe
and efficient when passed as arguments, because only a pointer to the
data is passed around, and the data is copied only if and when a
function writes to it, i.e., copy-on-write.
You can but you need not pass objects using implicit sharing by reference. They are designed to be passed by value efficiently!
Here you can find the complete explanation and the list of classes using implicit sharing. QString uses implicit sharing.
In Qt strings are implicitly shared and automatically copied on edit, so they are safe to pass even by value. It is still good practice to pass by reference though (in case it is not a QString), and it is even a tiny bit more efficient, since less data is copied, one memory address vs memory address, size and reference counting.
Generally speaking, it is a good idea to pass by reference when you want to modify the actual object inside the function (note that if you pass implicitly shared QString by value and modify it inside the function, this will not modify the original string but copy it and the changes will be lost after the function returns(unless you return the new string of course)), using references is a little more convenient than using pointers, and a little safer too. Also, if the object is larger than a primitive, or the object cannot/should not be copied, you can pass as reference. If you don't want to modify the source object, just make the reference const.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
References in VB.Net
I want to pass a medium large Customer db object, but I don't want to pass it by value, because I think it would be unnecessary.
In c++ when you had a large object it was inefficient to pass it by value, because a copy was created from it, so you passed it by reference so that there was no copy (of the object passed) created. I used to pass the parameter as a constant because that way if I tried to change the object inside the function the compiler wouldn't let me so that I wouldn't harm the passed object (because it was passed by reference). Is it possible to mimick this in vb.net or is it not needed?
My strong suspicion is that you're getting confused about how values are passed in VB.
If your CustomerDb type is a class, then every expression of that type will have a value which is already a reference. By default, that reference will be passed by value - but it's still only the reference which is passed, not a whole object.
If your CustomerDb type is a structure, then you really will be passing the whole value each time - and you should strongly consider changing it to a class anyway...
Of course, when you pass a reference by value, that doesn't stop the object from being modified within the method, but it does mean that changes to the parameter variable itself aren't reflected in the calling code.
Read my article on C# parameter passing - it's much the same in VB.
In .NET, classes (which I assume Customer is) are reference types. Passing a reference type as an argument will pass a reference (pointer) to the object. So passing a class is perfectly efficient and no copy is created.
If you pass a class by reference, then the method could change the reference (pointer) and it would be reflected in the calling method.
I don't know off the top of my head if there's an easy way to make the argument read only. Since reference types do pass a reference, any changes to the object will be reflected in the original. You might need a copy if you don't want the original to be modified.