is returning a const std::string really slower than non-const?

柔情痞子 提交于 2019-12-04 13:04:09

Consider the following functions:

std::string f();
std::string const g();

There is no difference between:

std::string s1 = f();
std::string s2 = g();

We have guaranteed copy elision now, in both of these cases we're constructing directly into the resulting object. No copy, no move.

However, there is a big difference between:

std::string s3, s4;
s3 = f(); // this is move assignment
s4 = g(); // this is copy assignment

g() may be an rvalue, but it's a const rvalue. It cannot bind to the string&& argument that the move assignment operator takes, so we fall back to the copy assignment operator whose string const& parameter can happily accept an rvalue.

Copying is definitely slower than moving for types like string, where moving is constant time and copying is linear and may require allocation.

Don't return const values.


On top of that, for non-class types:

int f();
int const g();

These two are actually the same, both return int. It's an odd quirk of the language that you cannot return a const prvalue of non-class type but you can return a const prvalue of class type. Easier to just pretend you can't do the latter either, since you shouldn't.

Without reading the specification or anything else, if we just think about it logically...

For example, lets say you have

// Declare the function
std::string const my_function();

// Initialize a non-constant variable using the function
std::string my_string = my_function();

The value returned by the function could be copied to a temporary object, the value from inside the function is then destructed. The temporary object (which is constant) is then copied to the my_string object, and then the temporary object is destructed. Two copies and two destructions. Sounds a little excessive, don't you think? Especially considering that both the value inside the function and the temporary object will be destructed, so they don't really need to keep their contents.

Wouldn't it be better if the copying could be elided, perhaps both of them? Then what could happen is that the value from inside the function is moved directly into the my_string object. The const status of anything doesn't matter, since the objects being moved from will be destructed next anyway.

The latter is what modern compiler do, they move even if the function is declared to return a const value. And even if the value or object inside the function is const as well.

Statements like this have certain meaning in terms of initialization,

std::string getString();
const std::string getConstantString();

std::string str = getString(); // 1
const std::string str = getConstantString(); //2

Both initialization statements 1 and 2 come under copy initialization. Now it depends on cv-qualification (const and volatile) of return type, there are two possibilities, if return type is cv-unqualified and move constructor available for class then object will be move initialized as in statement 1, and if return type is cv-qualified then object will be copy initialized as in statement 2.
But there is an optimization called copy-elision(ignores cv-qualification) and due to copy-elision, The objects are constructed directly into the storage where they would otherwise be copied/moved to.

There are two type of copy-elision, NRVO, "named return value optimization" and RVO, "return value optimization", but from c++17 Return value optimization is mandatory and no longer considered as copy elision.
Please see following link copy-elision for more details.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!