I've been back & forth with this problem for a while especially since I started to OpenCV library. The fact is, in OpenCV, there are several methods used:
1st: funcA((const) CvMat arg)
2nd: funcA((const) CvMat& arg)
3rd: funcA((const) CvMat* arg)
4th: funcA((const) CvMat*& arg) => I've just seen and currently been stuck at this
and of course, corresponding to each method, the caller format and the function implementation should be different.
What is the significance about all of these derivatives?? especially the last one (I've not yet understood its usage)
Ignoring the (const) for now, and using int for clarity:
Pass by value makes a copy in the body of the function
void funcA(int arg) {
// arg here is a copy
// anything I do to arg has no effect on caller side.
arg++; // only has effect locally
}
Note that it semantically makes a copy, but the compiler is allowed to elide the copies under certain conditions. Look up copy elision
Pass by reference. I can modify the argument passed by the caller.
void funcA(int& arg) {
// arg here is a reference
// anything I do to arg is seen on caller side.
arg++;
}
Pass pointer by value. I get a copy of the pointer, but it points to the same object pointed at by the caller's argument
void funcA(int* arg) {
// changes to arg do not affect caller's argument
// BUT I can change the object pointed to
(*arg)++; // pointer unchanged, pointee changed. Caller sees it.
}
Pass reference to pointer. I can change the pointed itself and the caller will see the change.
void funcA(int*& arg) {
// changes to arg affect caller's argument
// AND I can change the object pointed to.
(*arg)++; // pointee changed
arg++; // pointer changed. Caller sees it.
}
As you can see, the second two are just the same as the first two, except that they deal with pointers. If you understand what pointers do, then there is no difference conceptually.
Concerning const, it specifies whether the argument can be modified or not, or, if the arguments are references or pointers, whether what they point to/refer to can be modified. The positioning of const is important here. See const correctness for example.
Related
I'm learning C++ at the moment and try avoid picking up bad habits.
From what I understand, clang-tidy contains many "best practices" and I try to stick to them as best as possible (even though I don't necessarily understand why they are considered good yet), but I'm not sure if I understand what's recommended here.
I used this class from the tutorial:
class Creature
{
private:
std::string m_name;
public:
Creature(const std::string &name)
: m_name{name}
{
}
};
This leads to a suggestion from clang-tidy that I should pass by value instead of reference and use std::move.
If I do, I get the suggestion to make name a reference (to ensure it does not get copied every time) and the warning that std::move won't have any effect because name is a const so I should remove it.
The only way I don't get a warning is by removing const altogether:
Creature(std::string name)
: m_name{std::move(name)}
{
}
Which seems logical, as the only benefit of const was to prevent messing with the original string (which doesn't happen because I passed by value).
But I read on CPlusPlus.com:
Although note that -in the standard library- moving implies that the moved-from object is left in a valid but unspecified state. Which means that, after such an operation, the value of the moved-from object should only be destroyed or assigned a new value; accessing it otherwise yields an unspecified value.
Now imagine this code:
std::string nameString("Alex");
Creature c(nameString);
Because nameString gets passed by value, std::move will only invalidate name inside the constructor and not touch the original string. But what are the advantages of this? It seems like the content gets copied only once anyhow - if I pass by reference when I call m_name{name}, if I pass by value when I pass it (and then it gets moved). I understand that this is better than passing by value and not using std::move (because it gets copied twice).
So two questions:
Did I understand correctly what is happening here?
Is there any upside of using std::move over passing by reference and just calling m_name{name}?
/* (0) */
Creature(const std::string &name) : m_name{name} { }
A passed lvalue binds to name, then is copied into m_name.
A passed rvalue binds to name, then is copied into m_name.
/* (1) */
Creature(std::string name) : m_name{std::move(name)} { }
A passed lvalue is copied into name, then is moved into m_name.
A passed rvalue is moved into name, then is moved into m_name.
/* (2) */
Creature(const std::string &name) : m_name{name} { }
Creature(std::string &&rname) : m_name{std::move(rname)} { }
A passed lvalue binds to name, then is copied into m_name.
A passed rvalue binds to rname, then is moved into m_name.
As move operations are usually faster than copies, (1) is better than (0) if you pass a lot of temporaries. (2) is optimal in terms of copies/moves, but requires code repetition.
The code repetition can be avoided with perfect forwarding:
/* (3) */
template <typename T,
std::enable_if_t<
std::is_convertible_v<std::remove_cvref_t<T>, std::string>,
int> = 0
>
Creature(T&& name) : m_name{std::forward<T>(name)} { }
You might optionally want to constrain T in order to restrict the domain of types that this constructor can be instantiated with (as shown above). C++20 aims to simplify this with Concepts.
In C++17, prvalues are affected by guaranteed copy elision, which - when applicable - will reduce the number of copies/moves when passing arguments to functions.
Did I understand correctly what is happening here?
Yes.
Is there any upside of using std::move over passing by reference and just calling m_name{name}?
An easy to grasp function signature without any additional overloads. The signature immediately reveals that the argument will be copied - this saves callers from wondering whether a const std::string& reference might be stored as a data member, possibly becoming a dangling reference later on. And there is no need to overload on std::string&& name and const std::string& arguments to avoid unnecessary copies when rvalues are passed to the function. Passing an lvalue
std::string nameString("Alex");
Creature c(nameString);
to the function that takes its argument by value causes one copy and one move construction. Passing an rvalue to the same function
std::string nameString("Alex");
Creature c(std::move(nameString));
causes two move constructions. In contrast, when the function parameter is const std::string&, there will always be a copy, even when passing an rvalue argument. This is clearly an advantage as long as the argument type is cheap to move-construct (this is the case for std::string).
But there is a downside to consider: the reasoning doesn't work for functions that assign the function argument to another variable (instead of initializing it):
void setName(std::string name)
{
m_name = std::move(name);
}
will cause a deallocation of the resource that m_name refers to before it's reassigned. I recommend reading Item 41 in Effective Modern C++ and also this question.
How you pass is not the only variable here, what you pass makes the big difference between the two.
In C++, we have all kinds of value categories and this "idiom" exists for cases where you pass in an rvalue (such as "Alex-string-literal-that-constructs-temporary-std::string" or std::move(nameString)), which results in 0 copies of std::string being made (the type does not even have to be copy-constructible for rvalue arguments), and only uses std::string's move constructor.
Somewhat related Q&A.
There are several disadvantages of pass-by-value-and-move approach over pass-by-(rv)reference:
it causes 3 objects to be spawned instead of 2;
passing an object by value may lead to extra stack overhead, because even regular string class is typically at least 3 or 4 times larger than a pointer;
argument objects construction is going to be done on the caller side, causing code bloat;
Will the two function specifications below always compile to the same thing? I can't see that a copy would be needed if you're using const. If they aren't the same, why?
void(const int y);
void(const int& y);
Not the same. If the argument changes after it's passed (e.g. because it's changed by another thread), the first version is unaffected because it has a copy. In the second variant, the function called may not change the argument itself, but it would be affected by changes to y. With threads, this might mean it requires a mutex lock.
Without optimization ... this is not the same.
The first line of code gets a copy of the value passed into this function.
The second line of code gets the reference of the variable and your function will read the value always directly from the calling location variable .
In both cases the compiler is informed (by the keyword const), that these variables (inside the function) MUST not be modified. If there are any modifications in the function, an error will be generated.
The & specifies that the object is passed by reference (similar to passing by pointer at least on the assembly level). Thus
void fval(type x)
{
// x is a local copy of the data passed by the caller.
// modifying x has no effect on the data hold by the caller
}
type a;
fval(a); // a will not be changed
void fref(type &x)
{
// x is a mere reference to an object
// changing x affects the data hold by the caller
}
type b;
fref(b); // b may get changed.
Now adding the const keyword merely expresses that the function promises not to change the object.
void fcval(const type x)
{
// x is a local copy of the data passed by the caller.
// modifying x is not allowed
}
type a;
fcval(a); // a will not be changed
void fcref(const type &x)
{
// x is a mere reference to an object
// changing x is not allowed
}
type b;
fcref(b); // b will not be changed
Since a copy may be expensive, it should be avoided if not needed. Therefore, the method of choice for passing a constant object a la fcref (except for builtin types when fval is fast).
Just a general question say the signature of a function is:
void f( const string & s )...
Why is it necessary to pass this by reference if you are not actually changing the string (since it is constant)?
There are two alternatives to passing by reference - passing by pointer, and passing by value.
Passing by pointer is similar to passing by reference: the same argument of "why pass a pointer if you do not want to modify it" could be made for it.
Passing by value requires making a copy. Copying a string is usually more expensive, because dynamic memory needs to be allocated and de-allocated under the cover. That is why it is often a better idea to pass a const reference / pointer than passing a copy that you are not planning to change.
When you pass a variable by value, it makes a copy. Passing by reference avoids that copy. You want to mark it const for the same reason: Since you're not making a copy, you don't want to accidentally mess with the original. I think this could also potentially allow for compiler optimizations.
The reason you don't usually see this for int, char, float, and other primitive types is that they're relatively cheap to copy, and in some cases, passing by reference is more expensive (for example, passing a char by reference could involve passing 64-bits of data (the pointer) instead of 8-bits. Passing by reference also adds some indirection, which isn't a big deal with a big type like a string, but is wasteful for something like an int.
It is not "necessary," but the common answer is "for performance reasons, to prevent copying," however that is a naive answer and the truth is a bit more complex.
In your example, assuming s really is immutable and something you don't "own or can't change," then the const decorator is appropriate for s. If the reference of s wasn't taken, then that would guarantee a copied (excluding compiler optimizations).
If f() is not going to use the copy of s after f() returns, then the effort of copying s was wasted. So, passing by reference prevents the copying and f() retains the ability to inspect the string s. Great. And again, that's the naive answer and pre-C++11, would be the mostly correct answer.
There are more scenarios worth considering in order to answer "is it necessary?" but I'll focus on just one:
If the caller of f() doesn't need the string s after invoking
f(), but f() needs to retain a copy of the data.
Suppose the code is:
void f(const std::string& arg1); // f()'s signature
void g(const std::string& arg1) {
std::string s(arg1);
s.append(" mutate s");
f(s);
}
In this case, you would have constructed the string s, passed it by const reference to f(), and everything is fine from a performance perspective if you assume f() is opaque and there are no further optimizations available.
Now, suppose f() needs a copy of the data in s, then what? Well, f() will call a copy constructor and copy s in to a local variable:
// Hypothetical f()
void f(const std::string& s) {
this->someString_ = s;
}
In this case, by the time the data is stored in someString_, the normal constructor will have been called in g(), and the copy ctor will have been called in f(), however the work done in g() will have been wasted. To improve performance, there are two things that can be done, pass by value and/or use move constructors.
// Explicitly move arg1 in to someString_
void f(std::string&& arg1) {
this->somestring_ = std::move(arg1);
}
void g(const std::string& arg1) {
std::string s(arg1);
s.append(" mutate s");
f(s);
}
Which is explicitly doing what the compiler will automatically do starting with C++11, which means the more correct version is to pass by value and let the compiler do the right thing:
void f(std::string arg1) {
this->somestring_ = arg1; // Implicit move, let the compiler do the right thing
}
void g(const std::string& arg1) {
std::string s(arg1);
s.append(" mutate s");
f(s);
}
And in this case, the string is constructed in g() and no additional work was done anywhere. So in this case, the answer to,
Why is it necessary to pass this by reference if you are not actually
changing the string (since it is constant)?
The string wasn't changed, but it was copied, and therefore const reference was not necessary.
It's an exercise for the reader to list the optimizations the compiler can take when s is or isn't mutated after the call to f().
I can't recommend enough that people look in to David Abrams's post, 'Want Speed? Pass by value' or Is it better in C++ to pass by value or pass by constant reference? and post How to pass objects to functions in C++?.
in other words, you would get the speed of passing by reference ( not making extra copies ).
and the integrity of passing by value ( the original variable value is not changed)
It isn't 'necessary', but it's a very good idea, for several reasons:
Efficiency. Not creating or destroying new strings is more efficient than creating and destroying them, especially as strings are arbitrary in length and therefore require dynamically allocated memory.
A string can be constructed from a string literal. If you specify const you allow the compiler to construct a temporary string from a literal so that the caller can just provide the literal rather than the string object. If you don't specify const the compiler can't do that, so the caller can't do that either.
Let's take the following method as an example:
void Asset::Load( const std::string& path )
{
// complicated method....
}
General use of this method would be as follows:
Asset exampleAsset;
exampleAsset.Load("image0.png");
Since we know most of the time the Path is a temporary rvalue, does it make sense to add an Rvalue version of this method? And if so, is this a correct implementation;
void Asset::Load( const std::string& path )
{
// complicated method....
}
void Asset::Load( std::string&& path )
{
Load(path); // call the above method
}
Is this a correct approach to writing rvalue versions of methods?
For your particular case, the second overload is useless.
With the original code, which has just one overload for Load, this function is called for lvalues and rvalues.
With the new code, the first overload is called for lvalues and the second is called for rvalues. However, the second overload calls the first one. At the end, the effect of calling one or the other implies that the same operation (whatever the first overload does) will be performed.
Therefore, the effects of the original code and the new code are the same but the first code is just simpler.
Deciding whether a function must take an argument by value, lvalue reference or rvalue reference depends very much on what it does. You should provide an overload taking rvalue references when you want to move the passed argument. There are several good references on move semantincs out there, so I won't cover it here.
Bonus:
To help me make my point consider this simple probe class:
struct probe {
probe(const char* ) { std::cout << "ctr " << std::endl; }
probe(const probe& ) { std::cout << "copy" << std::endl; }
probe(probe&& ) { std::cout << "move" << std::endl; }
};
Now consider this function:
void f(const probe& p) {
probe q(p);
// use q;
}
Calling f("foo"); produces the following output:
ctr
copy
No surprises here: we create a temporary probe passing the const char* "foo". Hence the first output line. Then, this temporary is bound to p and a copy q of p is created inside f. Hence the second output line.
Now, consider taking p by value, that is, change f to:
void f(probe p) {
// use p;
}
The output of f("foo"); is now
ctr
Some will be surprised that in this case: there's no copy! In general, if you take an argument by reference and copy it inside your function, then it's better to take the argument by value. In this case, instead of creating a temporary and copying it, the compiler can construct the argument (p in this case) direct from the input ("foo"). For more information, see Want Speed? Pass by Value. by Dave Abrahams.
There are two notable exceptions to this guideline: constructors and assignment operators.
Consider this class:
struct foo {
probe p;
foo(const probe& q) : p(q) { }
};
The constructor takes a probe by const reference and then copy it to p. In this case, following the guideline above doesn't bring any performance improvement and probe's copy constructor will be called anyway. However, taking q by value might create an overload resolution issue similar to the one with assignment operator that I shall cover now.
Suppose that our class probe has a non-throwing swap method. Then the suggested implementation of its assignment operator (thinking in C++03 terms for the time being) is
probe& operator =(const probe& other) {
probe tmp(other);
swap(tmp);
return *this;
}
Then, according to the guideline above, it's better to write it like this
probe& operator =(probe tmp) {
swap(tmp);
return *this;
}
Now enter C++11 with rvalue references and move semantics. You decided to add a move assignment operator:
probe& operator =(probe&&);
Now calling the assignment operator on a temporary creates an ambiguity because both overloads are viable and none is preferred over the other. To resolve this issue, use the original implementation of the assignment operator (taking the argument by const reference).
Actually, this issue is not particular to constructors and assignment operators and might happen with any function. (It's more likely that you will experience it with constructors and assignment operators though.) For instance, calling g("foo"); when g has the following two overloads raises the ambiguity:
void g(probe);
void g(probe&&);
Unless you're doing something other than calling the lvalue reference version of Load, you don't need the second function, as an rvalue will bind to a const lvalue reference.
Since we know most of the time the Path is a temporary rvalue, does it make sense to add an Rvalue version of this method?
Probably not... Unless you need to do something tricky inside Load() that requires a non-const parameter. For example, maybe you want to std::move(Path) into another thread. In that case it might make sense to use move semantics.
Is this a correct approach to writing rvalue versions of methods?
No, you should do it the other way around:
void Asset::load( const std::string& path )
{
auto path_copy = path;
load(std::move(path_copy)); // call the below method
}
void Asset::load( std::string&& path )
{
// complicated method....
}
It's generally a question of whether internally you will make a copy (explicitly, or implicitly) of the incoming object (provide T&& argument), or you will just use it (stick to [const] T&).
If your Load member function doesn't assign from the incoming string, you should simply provide void Asset::Load(const std::string& Path).
If you do assign from the incoming path, say to a member variable, then there's a scenario where it could be slightly more efficient to provide void Asset::Load(std::string&& Path) too, but you'd need a different implementation that assigns ala loaded_from_path_ = std::move(Path);.
The potential benefit is to the caller, in that with the && version they might receive the free-store region that had been owned by the member variable, avoiding a pessimistic delete[]ion of that buffer inside void Asset::Load(const std::string& Path) and possible re-allocation next time the caller's string is assigned to (assuming the buffer's large enough to fit its next value too).
In your stated scenario, you're usually passing in string literals; such caller's will get no benefit from any && overload as there's no caller-owned std::string instance to receive the existing data member's buffer.
Here's what I do when trying to decide on the function signature
(const std::string& const_lvalue) argument is read only
(std::string& lvalue) I can modify argument (usually put something in) so the change would be VISIBLE to the caller
(std::string&& rvalue) I can modify argument (usually steal something from), zero consequences since the caller would no longer see/use this argument (consider it self destroyed after function returns) RVALUE reference bind to a temp object
All three of them are "pass-by-reference", but they show different intentions. 2+3 are similar, they can both modify the argument but 2 wants the modification to be seen by the caller whereas 3 doesn't.
// (2) caller sees the change argument
void ModifyInPlace(Foo& lvalue){
delete lvalue.data_pointer;
lvalue.data_pointer = nullptr;
}
// (3) move constructor, caller ignores the change to the argument
Foo(Foo&& rvalue)
{
this->data_pointer = that.data_pointer;
that.data_pointer = nullptr;
}
Explore more and find the answer to determine how to pass in old post (sorry for duplicate)
If the function intends to change the argument as a side effect, take
it by non-const reference.
If the function doesn't modify its
argument and the argument is of primitive type, take it by value.
Otherwise take it by const reference, except in the following cases
If the function would then need to make a copy of the const reference
anyway, take it by value.
[Original Post is Below]
I'd like to summarize the use of passing by value, const value, reference, const reference, pointer, const pointer and please correct me and give me your suggestions.
As for reference and pointer, use const if possible (thanks to all).
There is no performance difference between passing by reference and pointer.
When the size is not larger than a pointer (thanks to Mark Ransom), pass by value.
And some questions:
I seldom see passing by const value. Is it useful or the compiler will detect the const-ness in passing by value?
The const reference takes too much space. Can I just use passing by value? Will the modern compilers optimize it to not sacrifice the performance?
According the the article "Want Speed? Pass by Value" juanchopanza mentioned, I add one more item.
If you will copy your arguments, pass them by value and let the compiler do the copying other than passing them by const reference and doing the copy by yourself in the function body.
Thanks a lot!
I seldom see passing by const value. Is it useful or the compiler will detect the const-ness in passing by value?
Passing by const value doesn't really exist. When you pass by value, you can't modify the value in such a way that the changes will be visible outside of the subroutine. This is because when you pass by value, a copy is made of the original value and that copy is used in the function.
The const reference takes too much space. Can I just use passing by
value? Will the modern compilers optimize it to not sacrifice the
performance?
Passing by (const) reference is not the same as passing by value. When you pass by reference the value is NOT copied, a memory location is simply supplied and thus you may 'modify' (indirectly) the value that you pass by reference.
Take for example, the following:
void byValue(int x) {
x += 1
}
void byRef(int &x) {
x += 1
}
// ...
{
y = 10;
byValue(y);
cout << y << endl // Prints 10
byRef(y);
cout << y << endl; // Prints 11
}
// ...
Use const as much as possible.
Passing const where necessary is always a good idea. It helps code readability, lets others know what will happen to the values they pass to the method, and helps the compiler catch any mistakes you may make in modifying the value inside the method.
There is no performance difference between passing by reference and pointer.
A negligible amount, if any. The compiler will take care of the details here. It saves you the effort of creating a pointer, and it nicely dereferences it for you.
When the size is not larger than a word, pass by value.
As Mark points out, you do this if the value is smaller than a pointer. Pointers are different sizes on 32bit and 64bit systems (hence the name) and so this is really at your discretion. I'm a fan of passing pointers for nearly everything except the primitive types (char, int8_t, int16_t, float, etc), but that is just my opinion.