16

In this code:

#include <iostream>

int main(void)
{
    std::string {} = "hi";
    return 0;
}

This type of declaration is valid in C++. See in Godbolt.

  • What does it mean?
  • How is it valid?

For information, I tested this program from c++11 to c++20 flags as extended initializers are available from c++11 onwards.

Rohan Bari
  • 7,482
  • 3
  • 14
  • 34
  • 9
    You create an unnamed temporary `std::string` then call its `operator=(const char*)` – UnholySheep Nov 25 '22 at 14:01
  • Related? [Is it valid to declare a variable without a name](https://stackoverflow.com/questions/72249815/is-it-valid-to-declare-a-variable-without-a-name) – Jason Nov 25 '22 at 14:02
  • @JasonLiam Seems related except I'm assigning something to an unnamed variable. – Rohan Bari Nov 25 '22 at 14:06
  • 5
    Godbolt can take you to CppInsights, and, from there, if you click the play button, you will get an "insight" view (on the right hand side pane) of what's going on in the code: https://cppinsights.io/s/194c6e89 – rturrado Nov 25 '22 at 14:09
  • [Dupe1](https://stackoverflow.com/questions/65461889/why-can-i-use-assignment-operator-on-begin-even-if-it-is-an-rvalue), [Dupe2](https://stackoverflow.com/questions/33784044/assigning-to-rvalue-why-does-this-compile) and [Dupe3](https://stackoverflow.com/questions/21478485/prevent-assigning-to-rvalue). – Jason Nov 25 '22 at 14:09
  • I'm surprised to know that programmers voted to reopen this question. – Rohan Bari Nov 26 '22 at 07:52
  • @UnholySheep Not sure what you meant by "temporary `std::string`", but in case you meant there is a temporary materialization - why? Looking at [cpp reference](https://en.cppreference.com/w/cpp/language/implicit_conversion#Temporary_materialization) I couldn't find which case this would belong. – domdrag Feb 20 '23 at 11:25
  • @domdrag `std::string {}` - this creates an unnamed temporary via value initialization, see point 5 in https://en.cppreference.com/w/cpp/language/value_initialization. – UnholySheep Feb 20 '23 at 11:31
  • @UnholySheep Consider: `SomeClass C = SomeClass{};`. As far as I'm concered, `SomeClass{}` shouldn't be a temporary object here since we're doing copy initialization using prvalue of the same type (note at the bottom of [Temporary materialization](https://en.cppreference.com/w/cpp/language/implicit_conversion#Temporary_materialization)). Not sure what's up here. – domdrag Feb 20 '23 at 11:42

1 Answers1

20

std::string::operator=(const char*) is not &-qualified, meaning it allows assignment to lvalues as well as rvalues.

Some argue(1) that assignment operators should be &-qualified to ban assignment to rvalues:

(1) E.g. the High Integrity C++ standard intended for safety-critical C++ development, particularly rule 12.5.7 Declare assignment operators with the ref-qualifier &.

struct S {
    S& operator=(const S&) & { return *this; }
};

int main() {
    S {} = {};  // error: no viable overloaded '='
}

Or, more explicitly:

struct S {
    S& operator=(const S&) & { return *this; }
    S& operator=(const S&) && = delete;
};

int main() {
    S {} = {};  // error: overload resolution selected deleted operator '='
}
dfrib
  • 70,367
  • 12
  • 127
  • 192
  • Which means `std::string {} = "hi";` is basically a noop. It might still be valuable to mention the actual behaviour, not only the reason why you are allowed to write this statement. – JojOatXGME Dec 23 '22 at 01:03
  • @JojOatXGME Whether it's a noop or not depends on whether the assignment operator have side effects or not, including any side effects of the right hand side. [Value category is not lifetime](https://quuxplusone.github.io/blog/2019/03/11/value-category-is-not-lifetime/), and reasoning about lifetime-related behaviour when the key point is value categories will, imo, only promote the common misconception that value categories are strongly lifetime-related. – dfrib Dec 23 '22 at 09:25
  • I am aware of that. I only meant for the specific example of `std::string`. I.e. *"In the specific case of `std::string {} = "hi";`, the statement would be a noop. However, depending on the constructor, assignment operator, and maybe copy constructor, such expression could have side effects when using other types then `std::string`."* Anyway, it is not that important. If you think it might be misleading, you can leaf it as is. I just found it strage that you were basically ignoring the *"what does it mean"*-part. – JojOatXGME Dec 23 '22 at 16:03