c++ will compiler optimize argument by value to argument by rvalue reference? - c++

I think to recall that someone told me that these two methods
foo(std::vector<int>&& v) {
member = std::move(v);
}
bar(std::vector<int> v) {
member = std::move(v);
}
both will not invoke a copy if there is a move at the call site
foo(std::move(v1));
bar(std::move(v2));
since the compiler will optimize the call and treat the bar case as if it would take the argument by rvalue reference and therefore one should favor the bar syntax since it's less convoluted and can also be called with an lvalue (in which case of course a copy will be made).
Is this true? can one rely on the barcase not creating a copy so long as one calls it with an rvalue?

can one rely on the bar case not creating a copy so long as one calls it with an rvalue?
No, not necessarily.
An example in which a copy will take place:
const std::vector<int> vec;
bar( std::move(vec) );
Here std::move will cast vec (an lvalue) to an xvalue (i.e. rvalue). But it won't be moved since vec is constant and can not be modified. Thus the move constructor of std::vector won't be called.
Now I tried your code with a bit of modification in godbolt and I got the results that you expected.
This code:
#include <iostream>
#include <vector>
#include <utility>
void foo( std::vector<int>&& v )
{
auto member = std::move(v);
}
void bar( std::vector<int> v )
{
auto member = std::move(v);
}
int main( )
{
std::vector<int> v1(3, 1000);
std::vector<int> v2(3, 2000);
//foo( std::move(v1) ); // uncomment this
//bar( std::move(v2) ); // uncomment this
bar( v2 ); // and comment this out
for ( const auto& num : v1 )
{
std::cout << num << ' ';
}
std::cout << '\n';
for ( const auto& num : v2 )
{
std::cout << num << ' ';
}
std::cout << '\n';
}
First, you will see the output as:
1000 1000 1000
2000 2000 2000
But then do the things I mentioned above and you will see that the output will disappear. This is because after moving the two vectors, they will become empty due to losing ownership of their buffer. So the for-loops will print nothing. This really proves that a move is happening in bar( std::move(v2) );. And bar( v2 ); is a deep copy.

Related

Why this code does allow to push_back unique_ptr do vector?

so I thought adding unique to vector shouldn't work.
Why does it work for the below code?
Is it cause by not setting copy ctor as "deleted"??
#include <iostream>
#include <vector>
#include <memory>
class Test
{
public:
int i = 5;
};
int main()
{
std::vector<std::unique_ptr<Test>> tests;
tests.push_back(std::make_unique<Test>());
for (auto &test : tests)
{
std::cout << test->i << std::endl;
}
for (auto &test : tests)
{
std::cout << test->i << std::endl;
}
}
There is no copy here, only moves.
In this context, make_unique will produce an instance of unique pointer which is not named, and this push_back sees it as a r-value reference, which it can use as it wants.
It produce pretty much the same result than this code would:
std::vector<std::unique_ptr<Test>> tests;
auto ptr = std::make_unique<Test>();
tests.push_back(std::move(ptr));
This is called move semantics if you want to search more info on the matter. (and this only works from c++11 and beyond)
There are two overloads of std::vector::push_back according to https://en.cppreference.com/w/cpp/container/vector/push_back
In your case you will use the one with rvalue-ref so no copying required.

Create a temporary to pass to rvalue reference

I want to code several recursively interacting merge functions, which I think should have signatures: T&& merge_XYZ(T&& a, T&& b);
They will tend to be used recursively with lines such as:
return merge_XYZ( std::move(x), std::move(y) );
Each of these several merge functions will steal the contents of one of the inputs and inject those contents into the other input and return the result. Typically, they will have x and y which are names for what were rvalue references and thus should be converted back to rvalue references by std::move (correct me if I'm wrong).
But rarely, they have x and or y that are references to objects whose contents must not be stolen. I definitely don't want to write alternate non stealing versions of these functions. Rather, I want the caller to deal with that in these rare cases. So my main question is whether the correct way to do that is to explicitly invoke copy construction, such as:
T temp = merge_QRS( T(x), T(y) ); // use x and y without stealing yet
return merge_XYZ( merge_MNO( std::move(x), std::move(y) ), std::move(temp) );
Main question: Is T(x) the right way to force a temporary copy to be created at that point?
Other questions:
Is T temp = the correct way to make sure the call to merge_QRS in the above code occurs before the call to merge_MNO but otherwise inexpensively forward the temporary from that into the first operand of merge_XYZ? If I used T&& temp instead does it end up holding a pointer to modified T(x) after the life of T(x)?
Is T&& the right return type (as opposed to T) for chaining a lot of these together?
How does the above compare to:
T tx = x;
T&& temp = merge_QRS( std::move(tx), T(y) ); // use x and y without stealing yet
return merge_XYZ( merge_MNO( std::move(x), std::move(y) ), std::move(temp) );
Assuming merge_QRS will be modifying tx and returning an rvalue reference to that, is that behavior all defined?
Writing this question may have helped me realize I could be mixing together two situations that ought not to be mixed: Object you don't want to steal from vs. objects you don't want to steal from yet. Is my original merge_QRS( T(y), T(x)) right (only if consumed within the same expression) for objects I don't want to steal from? But in the case I tried as an example should I have the following:
T tx = x; // Make copies which can be stolen from
T ty = y;
return merge_XYZ( merge_MNO( std::move(x), std::move(y) ),
merge_QRS( std::move(tx), std::move(ty) ) );
I think I may still be confused about stealing the contents vs. stealing the identity. If I return by T&& I'm stealing the identity of one input in addition to stealing the contents of the other. When do I get away with stealing an identity? If I return by T I'm never stealing an identity, and sometimes failing to steal an identity is inefficient.
Main question: Is T(x) the right way to force a temporary copy to be created at that point?
Yes
Is T temp = the correct way to make sure the call to merge_QRS in the above code occurs before the call to merge_MNO but otherwise inexpensively forward the temporary from that into the first operand of merge_XYZ?
Yes
If I used T&& temp instead does it end up holding a pointer to modified T(x) after the life of T(x)?
Yes. That's dangling reference which unfortunately the compiler won't catch.
Is T&& the right return type (as opposed to T) for chaining a lot of these together?
To be honest, it doesn't smell good to me.
You may want to reconsider your data model to be something more standard, i.e.:
T merge(T x, T y)
{
// do some merging
return x;
}
Copy-elision and RVO will eliminate any redundant copies. Now you can move items in, pass copies or pass temporaries. There's only one piece of logic to maintain and your code has value-semantics... which is always better (TM).
tl;dr: With value semantics you get:
moves happening where possible
No need to explictly copy arguments
No dangling references in case of passing prvalues to the function
Consider
struct X
{
X() = default;
X(int y) : a(y) {}
X(X &&r) : a(r.a) { std::cout << "move X..."; }
X(X const &r) : a(r.a) { std::cout << "copy X..."; }
int a;
};
with foo:
X&& foo(X &&a) { return std::move(a); }
and and bar:
X bar(X a) { return a; }
Then when executing the following Code:
std::cout << "foo:\n";
X x{ 55 };
std::cout << "a: ";
X && a = foo(std::move(x)); // fine
std::cout << "\nb: ";
X && b = foo(X(x)); // !! dangling RV is not prvalue but xvalue
std::cout << "\nc: ";
X c = foo(std::move(x)); // fine, copy
std::cout << "\nd: ";
X d = foo(X(x)); // fine
std::cout << "\ne: ";
X && e = foo(X{ 12 }); // !! dangling...
std::cout << "\nf: ";
X f = foo(X{ 12 }); // fine
std::cout << "\n\nbar:\n";
X y{ 55 };
std::cout << "a: ";
X && q = bar(std::move(y)); // fine
std::cout << "\nb: ";
X && r = bar(y); // no explict copy required, supported by syntax
std::cout << "\nc: ";
X s = bar(std::move(y)); // fine
std::cout << "\nd: ";
X t = bar(y); // fine, no explict copy required either
std::cout << "\ne: ";
X && u = bar(X{ 12 }); // fine
std::cout << "\nf: ";
X v = bar(X{ 12 }); // fine
std::cout << "\n";
we obtain
foo:
a:
b: copy X...
c: move X...
d: copy X...move X...
e:
f: move X...
bar :
a: move X...move X...
b: copy X...move X...
c: move X...move X...
d: copy X...move X...
e: move X...
f: move X...
on VS 2015 and g++ 5.2.
So the only copies made (with bar) are in cases b and d, which is the desired behaviour anyway but you get rid of the possibly dangling references at the cost of 1-2 moves per operation (which afaik even may be optimized out in some cases as well).

How can a function in C++ return either a value or a reference with minimal copying?

I have a function that delegates to two others, returning either a reference or value depending on some runtime condition:
X by_value() { ... }
const X& by_reference() { ... }
?? foo(bool b) {
if (b) {
return by_value();
} else {
return by_reference();
}
}
I'd like to choose the return type of my function so that callers induce minimal copying; e.g.:
const X& x1 = foo(true); // No copies
const X& x2 = foo(false); // No copies
X x3 = foo(true); // No copies, one move (or zero via RVO)
X x4 = foo(false); // One copy
In all cases except the last, there shouldn't be a need (based on the runtime behavior) to copy the return value.
If the return type of foo is X, then there will be an extra copy in case 2; but if the return type is const X&, then cases 1 and 3 are undefined behavior.
Is it possible, via returning some sort of proxy, to ensure that the above uses have minimal copies?
Explanation: Since there's been significant pushback of the form "you're doing it wrong", I thought I'd explain the reason for this.
Imagine I have an array of type T or function<T()> (meaning the elements of this array are either of type T, or they're functions returning T). By the "value" of an element of this array, I mean, either the value itself or the return value when the function is evaluated.
If this get_value_of_array(int index) returns by value, then in the cases where the array contains just an element, I'm forced to do an extra copy. This is what I'm trying to avoid.
Further note: If the answer is, "That's impossible", that's fine with me. I'd love to see a proof of this, though - ideally of the form "Suppose there were a type Proxy<X> that solved your problem. Then...`
What you are looking for is a sum-type (that is, a type whose possible values are "the possible X values plus the possible X const& values").
In C++, these are usually called variant. These are usually implemented as a tag plus an appropriately sized and aligned array, and only hold exactly one value at runtime. Alternatively, they are implemented with dynamic allocation and the classic visitor pattern.
For example, with Boost.Variant, you could declare your function to return boost::variant<X, X const&> (live example):
boost::variant<X, X const&> foo(bool b) {
if (b) {
return by_value();
} else {
return by_reference();
}
}
I think this is impossible because whether the caller decides to move or copy the return value (whether it's from a proxy or from your class itself) is a compile-time decision, whereas what you want is to make it a run-time decision. Overload resolution cannot happen at run-time.
The only way out that I can see is to have the callee decide this, i.e. by providing a T & parameter which it can either move-assign to or copy-assign to depending on what it deems appropriate.
Alternatively, you can pass an aligned_storage<sizeof(T)> buffer and have the callee construct the value inside it, if you don't think the caller can be expected to make a "null" instance of some sort.
Well, if really want to achieve this, here's one rather ugly way:
X *foo(bool b, X *value) {
if (b) {
*value = get_value();
} else {
value = get_pointer_to_value();
}
return value;
}
Example usage:
void examplefunc() {
X local_store;
X *result;
result = foo(true, &local_store);
assert(result == &local_store);
use_x_value(*x);
result = foo(false, &local_store);
assert(result != &local_store);
use_x_value(*x);
}
Above approach is cumbersome: it needs two local variables and forces using the return value through a pointer. It also exposes a raw pointer, which can't be nicely converted to a smart pointer (putting local_store to heap to allow using a smart pointer would make this approach even more complex, not to mention add the overhead of heap allocation). Also, local_store is always default-constructed, but if you don't need to make examplefunc re-entrant, it can be made static (or use thread-local storage for multi-threaded version).
So I have hard time imagining where you would actually want to use this. It'd be simpler to always just return a copied value (and let compiler take care of copy elision when it can), or always return a reference, or maybe always return a shared_ptr.
Your goal is bad: Having multiple return types where one is a copy and the other is reference makes the function unpredictable.
Assuming foo is a member function of some classes A, B:
makes
X A::foo() { return X(); }
X foo a = A().foo()
well defined
and
const X& B::foo() { return some_internal_x; }
const X& b = B().foo()
a dangling reference
You may be able to accomplish what you want (still a bit fuzzy) by passing the variable type to get_value_of_array. This would allow it to return two different types and make adjustments based on whether the member of the array is a function or array.
struct X
{
X() { std::cout << "Construct" << std::endl; }
X(X const&) { std::cout << "Copy" << std::endl; }
X(X&&) { std::cout << "Move" << std::endl; }
};
const X array;
X function() { return X(); }
template<typename ReturnType>
ReturnType get_value_of_array(bool);
template<>
const X& get_value_of_array<const X&>(bool /*isarray*/)
{
// if (isarray == false) return the cached result of function()
return array; // gotta build the example yo!
}
template<>
X get_value_of_array<X>(bool isarray)
{
return isarray ? array : std::move(function());
}
int main()
{
// Optimizations may vary.
const X& x1 = get_value_of_array<decltype(x1)>(true); // No copies or moves
const X& x2 = get_value_of_array<decltype(x2)>(false); // No copies or moves.
X x3 = get_value_of_array<decltype(x3)>(true); // One copy, one move.
X x4 = get_value_of_array<decltype(x4)>(false); // Two moves.
}
Thanks to Cheers and hth. - Alf for the implementation of X.
At the time I'm writing this answer it's not a requirement that the argument to the function foo should be computed at run time, or should be allowed to be other than literally false or true, thus:
#include <utility>
#include <iostream>
namespace my {
using std::cout; using std::endl;
class X
{
private:
X& operator=( X const& ) = delete;
public:
X() {}
X( X const& )
{ cout << "Copy" << endl; }
X( X&& )
{ cout << "Move" << endl; }
};
} // my
auto foo_true()
-> my::X
{ return my::X(); }
auto foo_false()
-> my::X const&
{ static my::X const static_x; return static_x; }
#define foo( arg ) foo_##arg()
auto main() -> int
{
using namespace my;
cout << "A" << endl; const X& x1 = foo(true); // No copies
cout << "B" << endl; const X& x2 = foo(false); // No copies
cout << "C" << endl; X x3 = foo(true); // No copies, one move (or zero via RVO)
cout << "D" << endl; X x4 = foo(false); // One copy
}

const object initialization as `const Vect const_vect = Vect() << 1 << 2;`

Some hours ago I read this question in which the user initialized a const object as
const QList warnings = QList() << 0 << 3 << 7;
Indeed, this expression somehow hurt me because going against the concepts I have of const and of overloading operator<<.
I tried to define an operator<< possibly allowing for the mentioned expression and here is what I got:
typedef vector<int> Vect;
Vect operator<<(Vect v, const int i){ //ByVal v, This way it works, but at which cost?
v.push_back(i); //v is copied at every call!
return v;
};
//Here is where I build the object
const Vect const_vect = Vect() << 1 << 2;
//it works fine but I see massive overhead due to copies..#_#
//Just for testing
int main() {
for(auto e = const_vect.begin(); e!=const_vect.end() ; ++e){
cout << *e << " ";
}
return 0;
}
The previous code (which is also here) works fine.
The following, on the other hand, is the expression I would have expected from the definition of operator<<:
Vect& operator<<(Vect& v, const int i){ //ByRef v<-this I would have expected;
v.push_back(i); //however it can't work because receives and
return v; //returns reference to temporary object.
};
My question is: what am I missing? is the operator<< defined in QList differently implemented from mine, in particular, can it receive and return ByRef?
Secondly, is perhaps the aforementioned a standard procedure to initialize complex const objects?
Thirdly (maybe inconvenient), how would such an expression handled by the compiler? what is done at compile-time and what at run-time?

Wunused-but-set-variable warning with C++11 auto

I am getting a -Wunused-but-set-variable warning with GCC v4.6 with the code below:
for ( auto i : f.vertexIndices ) {
Sy_MatrixFuzzyHashable< Vector3f > wrapper( cp );
if ( !vMapper.contains( wrapper ) ) {
mesh.vertexNormals() << cp;
i.normal = mesh.vertexNormals().size() - 1;
} else {
i.normal = vMapper.value( wrapper );
}
}
The warning specifically is:
warning: variable 'i' set but not used [-Wunused-but-set-variable]
The warning would make sense if i was a copy of an element, but since vertexIndices is a QList object (an STL-compliant Qt container class) the range-based for loop should call the begin() and end() iterator getters, which will always return a non-const iterator (as long as the container is non-const - which it is).
I can't currently test if it is working as I think it should because I'm changing my code base to take advantage of the new C++11 features, so nothing compiles yet. But I was hoping someone could tell me if this warning is is nonsense, or if I have misunderstood auto and range-based for loops...
I think the issue is that your for loop, as written like this:
for ( auto i : f.vertexIndices )
is getting back a copy of the stored vertex, not a reference to it. The compiler warning here says that you're then setting the value of i but not reading it because you're modifying the temporary copy rather than the stored vertex.
If you change it to
for ( auto& i : f.vertexIndices )
then this problem should go away, since you're actually modifying the vertices stored internally.
Hope this helps!
You misunderstood auto. This loop:
for ( auto i : f.vertexIndices )
should really be :
for ( auto & i : f.vertexIndices )
http://en.wikipedia.org/wiki/Foreach_loop#C.2B.2B
illustrates an example but yes, it needs to be a reference object for the foreach
#include <iostream>
int main()
{
int myint[] = {1,2,3,4,5};
for (int& i: myint)
{
std::cout << i << std::endl;
}
}
or
#include <QList>
#include <QDebug>
int main() {
QList<int> list;
list << 1 << 2 << 3 << 4 << 5;
foreach (int i, list) {
qDebug() << i;
}
}
Courtesy of Wikipedia