Repeatedly moving a variable from lambda that has been move captured
Asked Answered
F

1

10

I have the following test code:

#include <iostream>
#include <string>

void printValue(std::string&& val)
{
    std::cout << "Got value: " << val << "\n";
}

int main() {

    std::string testValue = "Test Value";

    auto lambda = [testValue = std::move(testValue)]() mutable
    {
        printValue(std::move(testValue));
    };

    lambda();
    lambda();
    lambda();
}

I get the result:

Got value: Test Value
Got value: Test Value
Got value: Test Value

It it a valid assumption that moving an object from within lambda that has been move captured will always have the initial state that it was moved into the lambda with, or is this just an artifact of an object being in "valid but unspecified state"?

Ferrand answered 16/4, 2018 at 1:50 Comment(1)
std::move gives permission to move. It doesn't do anything else. The client who receives such a "moved" value may choose to move from it, or may not. In your example printValue chooses not to move from val.Overprint
B
21

std::move doesn't perform move operation; it just converts the argument to an rvalue. For your code, printValue takes the parameter by rvalue-reference, so the argument testValue will be passed via the reference. But the move operation is not performed on it then testValue won't get changed.

If you change val to pass-by-value, then the argument testValue will be moved into val, or you can add move operation explicitly like

void printValue(std::string&& val)
{
    std::cout << "Got value: " << val << "\n";
    std::string x = std::move(val);            // perform move operation on val
}

Both would cause the move operation to be performed 3 times, then you'll get different result, e.g. with clang,

Got value: Test Value
Got value: 
Got value: 

PS: As you said, after being move-constructed-from the object will be left in valid but unspecified state. The behavior above is not guaranteed by the standard although most implementations do so.

Br answered 16/4, 2018 at 1:54 Comment(5)
If printValue takes the string by value gcc gives same result as you show below aswell.Bakerman
@Bakerman Yes it has the same effect; testValue is moved into the parameter val.Br
Is std::string specified to clear its source, or does it leave it with unspecified contents, when move-constructed-from?Robalo
@Yakk It will be left in unspecified state.Br
@Yakk There is also a (tiny) potential performance advantage in allowing a valid but unspecified state vs. empty in common implementations, because it allows leaving the original string unchanged for SSO (small string optimization). However, for now, it seems all implementations clear the source string even if it is small.Britteny

© 2022 - 2024 — McMap. All rights reserved.