在另一个问题中,用户评论说,返回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>
答案 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
初始化语句1
和2
都处于复制初始化之下。现在,它取决于cv-qualification
的{{1}}(常量和易失性),有两种可能性,如果return type
是return type
并且cv-unqualified
可用于类,则对象将如语句move constructor
中的move initialized
一样,如果1
为return type
,则对象将为cv-qualified
,如语句copy initialized
中一样。
但是有一个名为2
(忽略copy-elision
)的优化,由于cv-qualification
,对象直接构造到存储中,否则将被复制/移动到该存储中。 / strong>
copy-elision
有两种类型,copy-elision
和NRVO, "named return value optimization"
,但是从RVO, "return value optimization"
开始,返回值优化是强制性的,不再被视为复制省略。
请参阅以下链接copy-elision
有关更多详细信息。