Does the inverse of std::move exist? [duplicate] - c++

This question already has answers here:
Function dual to std::move?
(3 answers)
Closed 9 years ago.
std::move can be used to explicitly allow move semantics when the move wouldn't be already allowed implicitly (such as often when returning a local object from a function).
Now, I was wondering (esp. in the context of local return and implicit move there), if there is such a thing as the inverse of std::movethat will prevent moving the object (but still allow copying).
Does this even make sense?

std::move converts an lvalue into an rvalue, and it does this essentially by static_cast. The closest to what I can think of as the opposite are these two type casts:
static_cast<T &>(/*rvalue-expression*/)
static_cast<const T&>(/*rvalue-expression*/)
An example of this can be seen below:
#include <iostream>
void f(const int &)
{ std::cout << "const-lval-ref" << std::endl; }
void f(int &&)
{ std::cout << "rval-ref" << std::endl; }
int main()
{
f(static_cast<const int &>(3));
return 0;
}
Casting the prvalue 3 to const int & ensures that the lvalue-overload of f is chosen.
In most contexts, you get this rvalue-to-lvalue modification automatically, simply by assigning to a variable:
int a = 3;
When you use a after this line, it will be an lvalue. This is true even when a is declared as rvalue reference:
int &&a = 3;
Here, too, a becomes an lvalue (basically because it "has a name").
The only situation where I can imagine an explicit cast to have any relevant effect is my first example above. And there, when dealing with prvalues like 3 or temporaries returned from function calls by copy, the only legal cast is to const-reference (a non-const-reference is not allowed to bind to a prvalue).

The solution to prevent an object to be moved is to make the move constructor of the object private, this way the object can't be moved but can be copied.
Example with move:
enter code here
#include <iostream>
class A {
public:
std::string s;
A() : s("test") {}
A(const A& o) : s(o.s) { std::cout << "move failed!\n";}
A(A&& o) : s(std::move(o.s)) { std::cout << "move was succesfull!\n"; }
};
int main(int argc, const char * argv[])
{
A firsObject;
A secondObject = std::move(firsObject);
return 0;
}
Example with move disabled:
#include <iostream>
class A {
public:
std::string s;
A() : s("test") {}
A(const A& o) : s(o.s) { std::cout << "move failed!\n";}
private:
A(A&& o) : s(std::move(o.s)) { std::cout << "move was succesfull!\n"; }
};
int main(int argc, const char * argv[])
{
A firsObject;
A secondObject = std::move(firsObject);
return 0;
}

template<class T>
T& unmove(T&& t)
{
return t;
}
This will change the value category of the argument expression to an lvalue, no matter what it was originally.
void f(const int&); // copy version
void f(int&&); // move version
int main()
{
int i = ...;
f(42); // calls move version
f(move(i)); // calls move version
f(i); // calls copy version
f(unmove(42)); // calls copy version
f(unmove(move(i))); // calls copy version
f(unmove(i)); // calls copy version
}

Related

Why is move-constructor not called? [duplicate]

This question already has answers here:
Why are rvalues references variables not rvalue?
(3 answers)
Closed 1 year ago.
I have the following piece of code:
#include <iostream>
struct T {
int a;
T() = default;
T(T& other) {
std::cout << "copy &\n";
}
T(T&& other) {
std::cout << "move &&\n";
}
};
void foo(T&& x) {
T y(x); // why is copy ctor called??????
}
int main() {
T x;
foo(std::move(x));
return 0;
}
I don't understand why copy constructor is preferred over move constructor even though foo() accepts rvalue-reference.
x is an lvalue itself, even its type is rvalue-reference. Value category and type are two independent properties.
Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;
You need to use std::move to convert it to rvalue, just same as using std::move on x in main().
void foo(T&& x)
{
T y(std::move(x));
}

Difference between && and no ref in return type [duplicate]

This question already has an answer here:
Difference between "return-by-rvalue-ref" & "return-by-value" when you return using std::move?
(1 answer)
Closed 6 years ago.
Is there a difference in behavior when the return type is explicitly declared rvalue vs no ref? According to the example below, there doesn't seem to be any difference.
#include <iostream>
#include <vector>
using namespace std;
struct A {
A(int x) : x_(x) {}
A(A&&) = default; // VC12 hasn't implemented default move
A(const A&) = delete;
A& operator=(A&&) = default;
A& operator=(const A&) = delete;
vector<int> x_;
};
struct B{
B(int x) : a_(x) {}
A&& foo1() { return move(a_); } // explicitly declared as rvalue
A foo2() { return move(a_); } // no ref
A a_;
};
int main() {
B b1(7);
A a1 = b1.foo1();
B b2(7);
A a2 = b2.foo2();
cout << a1.x_.size() << ' ' << a2.x_.size() << endl;
cout << b1.a_.x_.size() << ' ' << b2.a_.x_.size() << endl;
return 0;
}
This example has been compiled by Ideone's C++14 compiler (not sure of the exact version, I suspect it's gnu 5.1) and VC12 (Visual Studio 2013). The only minor difference is VC12 requires an explicit move implementation.
Edit: A related SO post said that the two function end up doing the same thing. However, "in many cases it allows the compiler to perform copy elision and elide the calls to the move constructor of the returned type, as permitted by paragraph 12.8/31 of the C++11 Standard". "Copy elision allows the compiler to create the return value of the function directly in the object."
Question 1: Copy elision should still happen when move is explicitly called, right?
Question 2:
When move is explicitly called on a lvalue (so a required called), A&& and A means the same behavior. When move is not explicitly called, meaning the compiler performs copy elision, A should be the only return type. Combining the two scenario above, can I conclude that return type A&& is not useful and only adds confusion?
With
A&& foo1() { return move(a_); }
A foo2() { return move(a_); }
foo1 returns a (rvalue) reference.
foo2 construct an object A with the move constructor.

C++ temporary object bound to argument and return value const references

I cannot get a clear idea of whether this is legal, even after looking at related questions on SO and reading the C++03 standard page 192 (http://cs.nyu.edu/courses/fall11/CSCI-GA.2110-003/documents/c++2003std.pdf). Is this legal and safe:
const MyClass& f(const MyClass& arg) {
return arg;
}
void some_other_function() {
const MyClass& reference = f(MyClass());
// Use reference.
}
It seems to me that it is.
As far as I know, you can't do this. While binding a temporary to a const reference is legal C++(and lengthens the lifetime of that temporary -- see GOTW 88), further binding a const ref to another const ref doesn't lengthen the lifetime of that temporary.
The quote from page 192(C++03 standard):
A temporary bound to a reference parameter in a function call (5.2.2)
persists until the completion of the full expression containing the
call
I think the standard is pretty explicit that using reference after // Use reference. is invalid. I modified your snippet to check it(Mac OS X, clang: Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)):
#include <iostream>
struct MyClass
{
~MyClass()
{
std::cout << "~MyClass()" << std::endl;
}
};
const MyClass& f(const MyClass& arg) {
std::cout << "f()" << std::endl;
return arg;
}
int main() {
const MyClass& reference = f(MyClass());
std::cout << "main()" << std::endl;
}
It outputs:
f()
~MyClass()
main()
In other words, unless both me and clang developers are misinterpreting the C++ standard, it is illegal.
I was unable to get a clear interpretation from the standard, so I decided to check what's the de facto standard. The following code:
#include <cstdio>
struct MyClass
{
MyClass() { printf("constructor\n"); }
~MyClass() { printf("destructor\n"); }
MyClass(const MyClass&) { printf("copy\n"); }
MyClass(MyClass&&) { printf("move\n"); }
};
const MyClass& f(const MyClass& arg) {
return arg;
}
int main()
{
{
printf("before construction\n");
const MyClass& reference = f(MyClass());
printf("after construction\n");
}
printf("outside scope\n");
}
Yields:
before construction
constructor
destructor
after construction
outside scope
For MSVC, clang and g++. Seems it is not legal according to our main compiler suppliers.
This question is similar to following question: Pass const Key_Type& to operator[] of std::map
The code below explains what exactly is happening
#include <iostream>
struct MyClass{
int member;
MyClass():member(0){
std::cout<<"MyClass ctr "<<std::endl;
}
MyClass(const MyClass& rhs){
std::cout<<"MyClass copy ctr "<<std::endl;
}
~MyClass(){
std::cout<<"MyClass dtr"<<std::endl;
member = -1;
}
};
void f2(const MyClass& obj){
std::cout<<"func "<<obj.member<<std::endl;
}
const MyClass& f3(){
return MyClass();
}
MyClass f4(){
return MyClass(); //ideally not a good idea, exception is
//http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
}
int main()
{
std::cout << "-----Faulty Case-----------"<<std::endl;
//reference returned by f3 is local to f3 call and
//is destructed as soon as f3() is out of stack
//and hence the reference in f2() is not valid
f2( f3() );
std::cout <<std::endl<< "-----Correct way-----------"<<std::endl;
//A temporary object is returned by f4 which is then referred by reference in f2.
//This reference is alive in stack of f2 and hence can be used inside
//f2 with valid results.
//As explained in following article, the refernce should remain
//alive in stack to use temporary objects.
//http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
f2( f4() );
//note in previous expression, f4 returns by value but still copy ctr is not invoked,
//this I believe is Return Value Optimization (might be compiler dependent)
return 0;
}
Output of this program would be:
Executing the program....
$demo
-----Faulty Case-----------
MyClass ctr
MyClass dtr
func -1
-----Correct way-----------
MyClass ctr
func 0
MyClass dtr

Overloading Based on L-Value versus R-Value

I found in a C++ book the following:
Although we will not be doing it in this book, you can overload a
function name (or operator) so that it behaves differently when used
as an l-value and when it is used as an r-value. (Recall that an
l-value means it can be used on the left-hand side of an assignment
statement.) For example, if you want a function f to behave
differently depending on whether it is used as an l-value or an
r-value, you can do so as follows:
class SomeClass {
public:
int& f(); // will be used in any l-value invocation const
const int& f( ) const; // used in any r-value invocation ...
};
I tried this and it didn't work:
class Foo {
public:
int& id(int& a);
const int& id(int& a) const;
};
int main() {
int a;
Foo f;
f.id(a) = 2;
a = f.id(a);
cout << f.id(a) << endl;
}
int& Foo :: id(int& a) {
cout << "Bar\n";
return a;
}
const int& Foo :: id(int& a) const {
cout << "No bar !\n";
return a;
}
Have I wrongly understood it ?
Either the book's example is flat-out wrong, or you copied the wrong example from the book.
class SomeClass {
public:
int& f(); // will be used in any l-value invocation const
const int& f( ) const; // used in any r-value invocation ...
};
With this code, when you call s.f() where s is an object of type SomeClass, the first version will be called when s is non-const, and the second version will be called when s is const. Value category has nothing to do with it.
Ref-qualification looks like this:
#include <iostream>
class SomeClass {
public:
int f() & { std::cout << "lvalue\n"; }
int f() && { std::cout << "rvalue\n"; }
};
int main() {
SomeClass s; s.f(); // prints "lvalue"
SomeClass{}.f(); // prints "rvalue"
}
Ofcourse the book is correct. Let me explain the workings of an example of what the author meant :
#include <iostream>
using namespace std;
class CO
{
int _m;
public:
CO(int m) : _m(m) {}
int& m() { return _m; } // used as an l-value
int const& m() const { return _m; } // used as an r-value
};
int main()
{
CO a(1);
cout << a.m() << endl;
a.m() = 2; // here used as an l-value / overload resolution selects the correct one
cout << a.m() << endl;
return 0;
}
Output is
1
2
What you misunderstood is the function signature. You see when you have an argument &arg (as in id(&arg)) you pretty much predefine the l-valuness of it, so returning it through a const or non const member function does not change a thing.
The author refers to a common writting style that allows for 'getters' and 'setters' to be declared with a signature different only in const qualifires yet compile and behave correctly.
Edit
To be more pedantic, the following phrase
Recall that an l-value means it can be used on the left-hand side of an assignment statement.
is not valid anymore. lr valuness applies to expressions, and the shortest way to explain it, is that an expression whose adress we can take, is an l-value; if it's not obtainable it's an r-value.
So the syntax to which the author refers to, enforces the member function to be used correctly (correct compilation / overload resolution) at both sides of the assignment operator. This nowdays is no longer relevant to lr valueness.
A const member function can only be called on a const object. It makes no difference what you do with the return value. In your example, f is non-const, so it always calls the non-const version of f(). Note that you can also overload on r-value references (&&) in C++11.

How may I forbid calls to const member function of an rvalue object in C++ 2011?

The following code
#include <vector>
#include <string>
#include <iostream>
std::string const& at(std::vector<std::string> const& n, int i)
{
return n[i];
}
std::vector<std::string> mkvec()
{
std::vector<std::string> n;
n.push_back("kagami");
n.push_back("misao");
return n;
}
int main()
{
std::string const& s = at(mkvec(), 0);
std::cout << s << std::endl; // D'oh!
return 0;
}
may lead to crash because the original vector is already destructed there. In C++ 2011 (c++0x) after rvalue-reference is introduced in, a deleted function declaration can be used to completely forbid calls to at if the vector argument is an rvalue
std::string const& at(std::vector<std::string>&&, int) = delete;
That looks good, but the following code still cause crash
int main()
{
std::string const& s = mkvec()[0];
std::cout << s << std::endl; // D'oh!
return 0;
}
because calls to member function operator [] (size_type) const of an rvalue object is still allowed. Is there any way can I forbid this kind of calls?
FIX:
The examples above is not what I did in real projects. I just wonder if C++ 2011 support any member function qualifying like
class A {
void func() rvalue; // Then a call on an rvalue object goes to this overload
void func() const;
};
FIX:
It's great, but I think C++ standard goes too far at this feature. Anyway, I have following code compiled on clang++ 2.9
#include <cstdio>
struct A {
A() {}
void func() &
{
puts("a");
}
void func() &&
{
puts("b");
}
void func() const &
{
puts("c");
}
};
int main()
{
A().func();
A a;
a.func();
A const b;
b.func();
return 0;
}
Thanks a lot!
No, and you shouldn't. How am I to do std::cout << at(mkvec(), 0) << std::endl;, a perfectly reasonable thing, if you've banned me from using at() on temporaries?
Storing references to temporaries is just a problem C++ programmers have to deal with, unfortunately.
To answer your new question, yes, you can do this:
class A {
void func() &; // lvalues go to this one
void func() &&; // rvalues go to this one
};
A a;
a.func(); // first overload
A().func(); // second overload
Just an idea:
To disable copying constructor on the vector somehow.
vector ( const vector<T,Allocator>& x );
Implicit copying of arrays is not that good thing anyway. (wondering why STL authors decided to define such ctor at all)
It will fix problems like you've mentioned and as a bonus will force you to use more effective version of your function:
void mkvec(std::vector<std::string>& n)
{
n.push_back("kagami");
n.push_back("misao");
}