Reputation: 165
I am a beginner in cpp so excuse me for this question.
I was reading that returning const val prevents move semantics. therefore I dont understand why the following code is compiled and works normally. is it because only temporary object is being created? in what cases the move semantics cannot being done? thank you in advance!
#include <iostream>
using namespace std;
const string foo()
{
return string("hello");
}
int main()
{
string other = std::move(foo());
}
Upvotes: 3
Views: 1313
Reputation: 38285
I was reading that returning const val prevents move semantics. therefore I dont understand why the following code is compiled and works normally.
When move semantics are prevented by some mechanism, this doesn't necessarily mean that the code doesn't compile. Often, it compiles happily, but an expected move construction turns out to be a copy instead.
Example: a type has a user provided copy ctor, which disables compiler-generated move ctors. When we think we move-construct, we don't.
struct Test {
Test() = default;
Test(const Test&) {}
};
Test t1;
Test t2{std::move(t1)}; // Copies!
in what cases the move semantics cannot being done?
Coming to your example, something that is const
-qualified can't be used to move-construct another object in any meaningful way. Move construction makes sense when resources can be easily transferred, but const
-ness prevents that. Example: a type has compiler-generate move and copy constructors, but we can't move-construct from a const
instance.
struct Test {
Test() = default;
};
const Test t1;
Test t2{std::move(t1)}; // Copies!
Besides, it doesn't make sense to move something that is returned by a function by value:
string other = std::move(foo());
When foo()
returns by value, you can move-construct from it, unless the return type is const
. Hence, to enable move-construction of other
:
std::string foo();
string other = foo();
Upvotes: 2
Reputation: 29985
std::move
doesn't actually move anything. It is just an "rvalue cast". You cast something to rvalue, and the move constructor / move assignment operator does the actual moving if possible. "If possible" part is the key. In your example the return value is already an rvalue, so std::move
literally does nothing. You may even get warnings like "nothing is moved". That is because the move constructor of std::string
takes an argument of type std::string&&
not const std::string&&
. Because of that, the copy constructor is called.
Upvotes: 2
Reputation: 2052
std::move
is just a unconditional cast to rvalue. In your case the return value of std::move(foo())
was const std::string&&
. And because move constructor does not take const argument, copy constructor was called instead.
struct C {
C() { std::cout << "constructor" << std::endl; }
C(const C& other) { std::cout << "copy constructor" << std::endl; }
C(C&& other) { std::cout << "move constructor" << std::endl; }
};
const C get() {
return C();
}
int main() {
C c(std::move(get()));
return 0;
}
Upvotes: 2