返回const std :: string真的比非const慢吗?

时间:2019-06-12 21:15:21

标签: c++ c++11 c++14

在另一个问题中,用户评论说,返回const std :: string会丢失移动构造效率,并且速度较慢。

分配此方法的返回字符串是否确实如此:

const std::string toJson(const std::string &someText);

const std::string jsonString = toJson(someText);

...确实比非const版本慢:

std::string toJson(const std::string &str);

std::string jsonString = toJson(someText);

在这种情况下,移动施工效率是什么意思?

我以前从未听说过该限制,并且不记得在分析器中看到过该限制。但是我很好奇。

编辑:有一个建议的问题,询问:What is move semantics?。虽然某些解释当然与效率有关,但它解释了什么移动语义的含义,但没有解决为什么返回const值可能对性能产生负面影响。 / p>

3 个答案:

答案 0 :(得分:12)

请考虑以下功能:

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

两者之间没有区别

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

我们现在已经保证复制省略,在这两种情况下,我们都直接构建到结果对象中。没有副本,没有动静。

但是,两者之间有很大的区别

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

g()可能是一个右值,但它是一个 const 右值。它不能绑定到移动赋值运算符采用的string&&参数上,因此我们回到 copy 赋值运算符,其string const&参数可以愉快地接受一个右值。

对于string之类的类型,复制绝对比移动慢,因为移动是固定时间,复制是线性的,可能需要分配。

不返回const值。


最重要的是,对于非类类型:

int f();
int const g();

这两个实际上是相同的,都返回int。您不能返回非类类型的const prvalue,但是您可以返回类类型的const prvalue,这是一种奇怪的语言。假装您也不能做后者,因为您不应该这样做。

答案 1 :(得分:1)

如果我们只是从逻辑上考虑它,则无需阅读规范或其他任何内容...

例如,假设您有

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

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

可以将函数返回的值复制到临时对象,然后销毁函数内部的值。然后将临时对象(常量)复制到my_string对象,然后销毁该临时对象。两份副本和两次销毁。听起来有点过分,您不觉得吗?尤其要考虑到函数中的值都将被破坏,因此它们实际上不需要保留其内容。

如果可以删除(也许两个都删除)会更好吗?然后可能发生的是将函数内部的值直接移到my_string对象中。 const的状态无关紧要,因为从其移出的对象无论如何都会被破坏。

后者是现代编译器的工作,即使声明该函数返回const值,它们也会移动。而且即使函数中的值或对象也是const

答案 2 :(得分:0)

这样的陈述在初始化方面具有一定的意义,

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

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

初始化语句12都处于复制初始化之下。现在,它取决于cv-qualification的{​​{1}}(常量和易失性),有两种可能性,如果return typereturn type并且cv-unqualified可用于类,则对象将如语句move constructor中的move initialized一样,如果1return type,则对象将为cv-qualified,如语句copy initialized中一样。
但是有一个名为2(忽略copy-elision)的优化,由于cv-qualification对象直接构造到存储中,否则将被复制/移动到该存储中。 / strong>

copy-elision有两种类型,copy-elisionNRVO, "named return value optimization",但是从RVO, "return value optimization"开始,返回值优化是强制性的,不再被视为复制省略。
请参阅以下链接copy-elision 有关更多详细信息。