Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will returning a const object from a function prevent move construction from outside?

Given this functions and function call:

std::string GetString() {
  std::stringstream sstr;
  const auto str = sstr.str();
  return str;
}

const auto returnedStr = GetString();

Will the move-construction be omitted as I declare str as const?

like image 367
Viktor Sehr Avatar asked Sep 11 '14 10:09

Viktor Sehr


People also ask

What does it mean to return a const type from a function?

If you say that a function's return value is const: const int g(); you are promising that the original variable (inside the function frame) will not be modified. And again, because you're returning it by value, it's copied so the original value could never be modified via the return value.

Can you move a const value?

Expert #2: “You cannot move from a variable marked as const, and instead the copy-constructor/assignment will be invoked more often.

Can return type be const?

(C++) const return typeThe value of a return type that is declared const cannot be changed. This is especially useful when giving a reference to a class's internals (see example #0), but can also prevent rarer errors (see example #1). Use const whenever possible [1-7].


2 Answers

In your case, returnedStr will be move-constructed from the return value of GetString(), but that return value will be copy-constructed from str(1). If str wasn't const, the return value would be move-constructed from it.

Note that in both cases, return value optimisation is still applicable, so the compiler can still construct the return value (or even str itself) directly in the space of returnedStr, skipping one or both copy/move constructions. This is granted by C++11 12.8/31:

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization. This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

  • in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value

  • ...

  • when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

The first bullet point covers the elision of the return value construction, the other one covers moving the return value into returnedStr. Notice the requirement on "the same cv-unqualified" type, which means that this works regardless of cv qualifiers.


(1) Note that if we were talking about a class X other than std::string, one which provided a move constructor taking a const X&&, then indeed the return value would be move constructed using this constructor (whatever semantics it might have).

like image 60
Angew is no longer proud of SO Avatar answered Oct 03 '22 09:10

Angew is no longer proud of SO


Angew's answer is right but who can remember all the language lawyer rules?

To help me remember it easier I wrote the following rules which came from STL's own mouth.

  1. Don't return locals as const [16]

$ Inhibits move semantics

  1. Don't use move when returning local by value of exact same type [16]

$ NVRO won't be used if you do this.

  1. Don't return by Rvalue reference (&&) [16]

$ Unless you really really know what you're doing.

Notes:

[16] Don't Help the Compiler, Going Native 2013, http://www.youtube.com/watch?v=AKtHxKJRwp4

like image 39
Surt Avatar answered Oct 03 '22 09:10

Surt