Do I need to use std::move again? - c++11

For below code, I want to use the std::move to improve the efficiency. I have two functions, the first function uses std::move, and the second function just calls the first function. So, do I need to use std::move again in the function "vector convertToString()"? Why and why not? Thank you.
class Entity_PortBreakMeasure
{
public:
Entity_PortBreakMeasure(){}
int portfolioId;
string portfolioName;
int businessDate;
string assetType;
string currency;
string country;
string industry;
string indicator;
double value;
inline double operator()()
{
return value;
}
static vector<string> convertToString(Entity_PortBreakMeasure& pbm)
{
//PORTFOLIOID INDUSTRY CURRENCY COUNTRY BUSINESSDATE ASSETTYPE INDICATOR VALUE PORTFOLIONAME
vector<string> result;
result.push_back(boost::lexical_cast<string>(pbm.portfolioId));
result.push_back(pbm.industry);
result.push_back(pbm.currency);
result.push_back(pbm.country);
result.push_back(Date(pbm.businessDate).ToString());
result.push_back(pbm.assetType);
result.push_back(pbm.indicator);
result.push_back(boost::lexical_cast<string>(pbm.value));
result.push_back(pbm.portfolioName);
return std::move(result);
}
vector<string> convertToString()
{
return convertToString(*this);
}

move() shouldn't be used for either of these functions.
In the first function, you're returning a local variable. Without move(), most (all?) compilers will perform NRVO and you won't get a copy or a move -- the returned variable will be constructed directly in the returned value for the caller. Even if the compiler is, for some reason, unable to do NRVO, local variables become r-values when used as the argument to a return, so you'll get a move anyway. Using move() here serves only to inhibit NRVO and force the compiler to do a move (or a copy in the event that the move isn't viable).
In the second function, you're returning an r-value already, since the first function returns by value. move() here doesn't add anything but complexity (which might possibly confuse an optimizer into producing suboptimal code or failing to do copy elision).

Related

Casting to rvalue reference to "force" a move in a return value - clarification

Ok, I am starting to get the jist of rvalue references (I think). I have this code snippet that I was writing:
#include <iostream>
using namespace std;
std::string get_string()
{
std::string str{"here is your string\n"};
return std::move(str); // <----- cast here?
}
int main ()
{
std::string my_string = std::move(get_string()); // <----- or cast here?
std::cout << my_string;
return 0;
}
So I have a simple example where I have a function that returns a copy of a string. I have read that its bad (and got the core-dumps to prove it!) to return any reference to a local temp variable so I have discounted trying that.
In the assignment in main() I don't want to copy-construct that string I want to move-construct/assign the string to avoid copying the string too much.
Q1: I return a "copy" of the temp var in get_string() - but I have cast the return value to rvalue-red. Is that pointless or is that doing anything useful?
Q2: Assuming Q1's answer is I don't need to do that. Then am I moving the fresh copy of the temp variable into my_string, or am I moving directly the temp variable str into my_string.
Q3: what is the minimum number of copies that you need in order to get a string return value stored into an "external" (in my case in main()) variable, and how do you do that (if I am not already achieving it)?
I return a "copy" of the temp var in get_string() - but I have cast the return value to rvalue-red. Is that pointless or is that doing anything useful?
You don't have to use std::move in that situation, as local variables returned by value are "implicitly moved" for you. There's a special rule in the Standard for this. In this case, your move is pessimizing as it can prevent RVO (clang warns on this).
Q2: Assuming Q1's answer is I don't need to do that. Then am I moving the fresh copy of the temp variable into my_string, or am I moving directly the temp variable str into my_string.
You don't need to std::move the result of calling get_string(). get_string() is a prvalue, which means that the move constructor of my_string will automatically be called (pre-C++17). In C++17 and above, mandatory copy elision will ensure that no moves/copies happen (with prvalues).
Q3: what is the minimum number of copies that you need in order to get a string return value stored into an "external" (in my case in main()) variable, and how do you do that (if I am not already achieving it)?
Depends on the Standard and on whether or not RVO takes place. If RVO takes place, you will have 0 copies and 0 moves. If you're targeting C++17 and initializing from a prvalue, you are guaranteed to have 0 copies and 0 moves. If neither take place, you'll probably have a single move - I don't see why any copy should occur here.
You do not need to use std::move on the return value which is a local variable. The compiler does that for you:
If expression is an lvalue expression that is the (possibly parenthesized) name of an automatic storage duration object declared in the body or as a parameter of the innermost enclosing function or lambda expression, then overload resolution to select the constructor to use for initialization of the returned value is performed twice: first as if expression were an rvalue expression (thus it may select the move constructor), and if no suitable conversion is available, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed a second time, with expression considered as an lvalue (so it may select the copy constructor taking a reference to non-const).

Automatically call move constructors

I have the following code sample:
void MyClass::Register2(std::string name, std::string email)
{
m_name = std::move(name);
m_email = std::move(email);
}
void MyClass::Register1(std::string name)
{
Register2(std::move(name), "invalid_email");
}
My questions are:
Do I need to use std::move when calling Register2() from Register1()?
Do I need to call std::move() inside Register1()?
If the answer for question 2. is yes, would be possible to have a dedicated operator instead?
For example:
void MyClass::Register2(std::string name, std::string email)
{
m_name <= name; // perform move
m_email <= email; // perform move
}
Do I need to use std::move when calling Register2() from Register1()?
Yes, because name is an lvalue and you want to turn it into an rvalue.
Do I need to call std::move() inside Register1()?
Yes, for the same reason as above.
If the answer for question 2. is yes, would be possible to have a dedicated operator instead?
It would be possible, but I do not think it has been proposed. Also, if it were to be proposed, I do not think it would be accepted as it doesn't bring much value over std::move.
Yes
Yes
No
std::move looks something like this
template<typename T>
std::remove_reference_t<T>&& move(T&& value) {
return static_cast<std::remove_reference_t<T>&&>(value);
}
All it does is it casts the thing you pass as the argument to an rvalue. This step is essential because arguments, even if you pass an rvalue, are always lvalues (because they have names). Lvalues are not moveable, therefore if you don't cast them to an rvalue, move mechanics won't kick in and they will be simply copied.
Operators are functions and there are no exceptions in this case. Special move operator hasn't been proposed and is extremly unlikely to be because it would make the standard longer and more complex (compilers would also be heavily affected) for a feature that saves a couple chars.

refactor lambda to be called by another class: while keeping caller's code to be still short

How to professionally refactor lambda function to be called by another class WHILE make caller's code still short?
My attempt shows that for changing a lambda function to a normal function, I have to capture variables manually, thus the new normal function requires more parameters (to compensate automatic capture ability).
As a result, the new function is more tedious to use, and can cause more bug.
Example
Here is my original code, using lambda.
void Turret::registerFullversion(int gameObjectId, PhysicObject* phyO){//utility
//.... something a bit complex .......
}
void Turret::createTurret(int typeOfTurret){
int gameObjectId=createNewGameObjectId();
auto registerEasy=[&]( PhysicObject* phyO){
//^ served as a short hand version of "registerFullversion"
// 1 parameter is more comfortable than 2
registerFullversion(gameObjectId,phyO);
}
switch(typeOfTurret){
case 1:{ //this part will be moved into another class (###)
PhysicObject* phy=PhysicSystem::createNewPhysicObject();
registerEasy( phy);
//^ equivalent to "registerFullversion(gameObjectId,phy)"
// but it is very concise (1 parameter), nice!
};break;
//..... a lot of case ....
}
//... do something about "gameObjectId"
}
I want to move a part of function (###) from Turret into another class (TurretLaser).
It works, but the result is that caller have to capture gameObjectId and pass it manually :-
void Turret::createTurret(int typeOfTurret){
int gameObjectId=createNewGameObjectId();
switch(typeOfTurret){
case 1:{ //this part have to be move into another class
TurretLaser::createTurret(gameObjectId)
};break;
//..... a lot of case ....
}
}
void TurretLaser::createTurret(int gameObjectId){ //(###)
PhysicObject* phy=PhysicSystem::createNewPhysicObject();
Turret:registerFullversion(gameObjectId,phy);
//^ it is not as short as before (now = 2 parameters)
}
Note
In real case, all above functions are non-static function, and all functions are far more complex.
Performance is the first priority. Thus, std::bind and std::function are not allowed.
This question asks about how to omit the captured parameters rather than "Please fix my code", so a valid solution can also just provide a new example with its own fix instead of showing modification of my code.
My attempt
I will manually capture the related data (gameObjectId) and cache it (using a new variable CACHE_gameObjectId):-
void Turret::registerEasy(PhysicObject* physicO){
registerFullversion(CACHE_gameObjectId,physicO);
//int "CACHE_gameObjectId" is a new field of "Turret"
};
void Turret::createTurret(int typeOfTurret){
int gameObjectId=createNewGameObjectId();
Turret::CACHE_gameObjectId=gameObjectId;
switch(typeOfTurret){
case 1:{ //this part have to be move into another class
TurretLaser::createTurret(gameObjectId)
};break;
//..... a lot of case ....
}
}
void TurretLaser::createTurret(int gameObjectId){ //(###)
PhysicObject* phy=PhysicSystem::createNewPhysicObject();
Turret:registerEasy(phy);
//^ short as before, nice
}
Disadvantage of my solution: dirty, look dangerous (not so automatic, thus can cause more bug) , seem to be less thread-safe (?)

Move constructor not getting called? (C++11)

In the following example, why doesn't the move constructor get called in the construction of 'copy' inside fun, even though the 'src' argument of 'fun' is explicitly a rvalue reference and is only used in that construction?
struct Toy {
int data;
Toy(): data(0)
{
log("Constructed");
}
Toy(Toy const& src): data(src.data)
{
log("Copy-constructed");
}
Toy(Toy&& src): data(src.data)
{
log("Move-constructed");
}
};
Toy fun(Toy&& src)
{
Toy copy(src);
copy.data = 777;
return copy;
}
Toy toy(fun(Toy())); // LOG: Constructed Copy-constructed
While Bob && b is an rvalue reference, all named use of data after construction is using it as an lvalue.
So Bob&& b will only bind to rvalues, but when you use it it will not move.
The only ways to get an rvalue reference are:
A value without a name, such as a temporary return value or result of a cast.
Use of a local value variable in a simple return x; statement.
Explicitly casting to an rvalue, such as with std::move or std::forward.
This prevents data from being silently moved from on one line and then used on the next. It can help to think of rvalue as being 'I the programmer say this is not needed after this expression' at use, and 'only take things that are not needed afterwards' in function parameters. The temporary/return exceptions above are two spots the compiler can relatively safely guarantee this itself.
Finally, note that universal references (auto&& and T&&) look like rvalue references but sometimes are not.

Why would const-ness of a local variable inhibit move semantics for the returned value?

struct STest : public boost::noncopyable {
STest(STest && test) : m_n( std::move(test.m_n) ) {}
explicit STest(int n) : m_n(n) {}
int m_n;
};
STest FuncUsingConst(int n) {
STest const a(n);
return a;
}
STest FuncWithoutConst(int n) {
STest a(n);
return a;
}
void Caller() {
// 1. compiles just fine and uses move ctor
STest s1( FuncWithoutConst(17) );
// 2. does not compile (cannot use move ctor, tries to use copy ctor)
STest s2( FuncUsingConst(17) );
}
The above example illustrates how in C++11, as implemented in Microsoft Visual C++ 2012, the internal details of a function can modify its return type. Up until today, it was my understanding that the declaration of the return type is all a programmer needs to know to understand how the return value will be treated, e.g., when passed as a parameter to a subsequent function call. Not so.
I like making local variables const where appropriate. It helps me clean up my train of thought and clearly structure an algorithm. But beware of returning a variable that was declared const! Even though the variable will no longer be accessed (a return statement was executed, after all), and even though the variable that was declared const has long gone out of scope (evaluation of the parameter expression is complete), it cannot be moved and thus will be copied (or fail to compile if copying is not possible).
This question is related to another question, Move semantics & returning const values. The difference is that in the latter, the function is declared to return a const value. In my example, FuncUsingConst is declared to return a volatile temporary. Yet, the implementational details of the function body affect the type of the return value, and determine whether or not the returned value can be used as a parameter to other functions.
Is this behavior intended by the standard?
How can this be regarded useful?
Bonus question: How can the compiler know the difference at compile time, given that the call and the implementation may be in different translation units?
EDIT: An attempt to rephrase the question.
How is it possible that there is more to the result of a function than the declared return type? How does it even seem acceptable at all that the function declaration is not sufficient to determine the behavior of the function's returned value? To me that seems to be a case of FUBAR and I'm just not sure whether to blame the standard or Microsoft's implementation thereof.
As the implementer of the called function, I cannot be expected to even know all callers, let alone monitor every little change in the calling code. On the other hand, as the implementer of the calling function, I cannot rely on the called function to not return a variable that happens to be declared const within the scope of the function implementation.
A function declaration is a contract. What is it worth now? We are not talking about a semantically equivalent compiler optimization here, like copy elision, which is nice to have but does not change the meaning of code. Whether or not the copy ctor is called does change the meaning of code (and can even break the code to a degree that it cannot be compiled, as illustrated above). To appreciate the awkwardness of what I am discussing here, consider the "bonus question" above.
I like making local variables const where appropriate. It helps me clean up my train of thought and clearly structure an algorithm.
That is indeed a good practice. Use const wherever you can. Here, however, you cannot (if you expect your const object to be moved from).
The fact that you declare a const object inside your function is a promise that your object's state won't ever be altered as long as the object is alive - in other words, never before its destructor is invoked. Not even immediately before its destructor is invoked. As long as it is alive, the state of a const object shall not change.
However, here you are somehow expecting this object to be moved from right before it gets destroyed by falling out of scope, and moving is altering state. You cannot move from a const object - not even if you are not going to use that object anymore.
What you can do, however, is to create a non-const object and access it in your function only through a reference to const bound to that object:
STest FuncUsingConst(int n) {
STest object_not_to_be_touched_if_not_through_reference(n);
STest const& a = object_not_to_be_touched_if_not_through_reference;
// Now work only with a
return object_not_to_be_touched_if_not_through_reference;
}
With a bit of discipline, you can easily enforce the semantics that the function should not modify that object after its creation - except for being allowed to move from it when returning.
UPDATE:
As suggested by balki in the comments, another possibility would be to bind a constant reference to a non-const temporary object (whose lifetime would be prolonged as per ยง 12.2/5), and perform a const_cast when returning it:
STest FuncUsingConst(int n) {
STest const& a = STest();
// Now work only with a
return const_cast<STest&&>(std::move(a));
}
A program is ill-formed if the copy/move constructor [...] for an object is implicitly odr-used and the special member function is not accessible
-- n3485 C++ draft standard [class.copy]/30
I suspect your problem is with MSVC 2012, and not with C++11.
This code, even without calling it, is not legal C++11:
struct STest {
STest(STest const&) = delete
STest(STest && test) : m_n( std::move(test.m_n) ) {}
explicit STest(int n) : m_n(n) {}
int m_n;
};
STest FuncUsingConst(int n) {
STest const a(n);
return a;
}
because there is no legal way to turn a into a return value. While the return can be elided, eliding the return value does not remove the requirement that the copy constructor exist.
If MSVC2012 is allowing FuncUsingConst to compile, it is doing so in violation of the C++11 standard.

Resources