I am bit puzzled about how standard governs this case:
struct Foo {
Foo & operator = (std::string xxx)
{
x = std::move(xxx);
return *this;
}
std::string x;
};
std::map<std::string, Foo> bar;
std::string baz = "some string";
bar[baz] = std::move(baz);
Can compilers produce code so that baz
will be moved before it's used to initialise and get reference to element in bar
(to initialise std::string xxx
)? Or is this code safe and there's no undefined behaviour?
Hell no. The expression is, yes, equivalent to
(bar.operator[](baz)).operator=(std::move(baz))
But there is no guaranteed order between the evaluation of (bar.operator[](baz)).operator=
- formally, the postfix-expression designating the function to be called - and the evaluation of the initialization of the argument to operator=
, which is what moves from baz
.
In fact, this asserts on GCC:
std::map<std::string, Foo> bar;
std::string baz = "some string";
bar[baz] = std::move(baz);
assert(bar.count("some string"));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With