C++ 返回常量std::string真的比非常量慢吗?
在另一个问题中,一位用户评论说,返回const std::string会降低移动构造效率,速度也会变慢 分配此方法的返回字符串是否为真:C++ 返回常量std::string真的比非常量慢吗?,c++,c++11,c++14,C++,C++11,C++14,在另一个问题中,一位用户评论说,返回const std::string会降低移动构造效率,速度也会变慢 分配此方法的返回字符串是否为真: const std::string toJson(const std::string &someText); const std::string jsonString = toJson(someText); 。。。确实比非常量版本慢: std::string toJson(const std::string &str); std::str
const std::string toJson(const std::string &someText);
const std::string jsonString = toJson(someText);
。。。确实比非常量版本慢:
std::string toJson(const std::string &str);
std::string jsonString = toJson(someText);
在这种情况下,移动施工效率的含义是什么
我以前从未听说过这种限制,也不记得在分析器中看到过。但我很好奇
编辑:有一个建议的问题询问:。虽然一些解释当然与效率有关,但它解释了移动语义的含义,但没有说明返回常量值可能会对性能产生负面影响的原因。考虑以下功能:
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
我们现在已经保证了拷贝省略,在这两种情况下,我们都直接构建到结果对象中。不复制,不移动
然而,这两者之间有很大的区别:
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()
可能是右值,但它是常量右值。它不能绑定到move赋值操作符所使用的string&
参数,因此我们回到copy赋值操作符,它的string const&
参数可以愉快地接受右值
对于像string
这样的类型,复制肯定比移动慢,移动是固定时间,复制是线性的,可能需要分配
不要返回常量值
除此之外,对于非类类型:
int f();
int const g();
这两者实际上是相同的,都返回
int
。这种语言的一个奇怪之处是,不能返回非类类型的constprvalue,但可以返回类类型的constprvalue。假装你也做不到后者更容易,因为你不应该这样做 如果我们只是从逻辑上考虑,就不必阅读规范或其他任何内容
例如,假设您有
// Declare the function
std::string const my_function();
// Initialize a non-constant variable using the function
std::string my_string = my_function();
函数返回的值可以复制到临时对象中,然后函数内部的值被销毁。然后将临时对象(常量)复制到my_string
对象,然后销毁临时对象。两份拷贝和两份销毁。听起来有点过分,你不觉得吗?特别是考虑到函数内的值和临时对象都将被破坏,因此它们实际上不需要保留其内容
如果复制品可以省略掉,也许两者都可以,不是更好吗?然后可能发生的情况是,函数内部的值直接移动到myu字符串
对象中。任何东西的const
状态都无关紧要,因为要从中移动的对象下一步无论如何都会被销毁
后者是现代编译器所做的,即使函数声明为返回
const
值,它们也会移动。即使函数中的值或对象也是常量。这样的语句在初始化方面有一定的意义
std::string getString();
const std::string getConstantString();
std::string str = getString(); // 1
const std::string str = getConstantString(); //2
初始化语句1
和2
都属于复制初始化。现在它取决于返回类型
的cv限定
(常量和volatile),有两种可能性,如果返回类型
是cv不合格的
,并且类可用移动构造函数
,则对象将被移动初始化
,如语句1
所示,如果返回类型
是cv限定的
,则对象将被复制初始化
,如语句2
但是有一种优化称为
复制省略
(忽略cv限定
),由于复制省略
,对象被直接构造到存储中,否则它们将被复制/移动到存储中。有两种类型的
copy elision
,NRVO,“命名返回值优化”
和RVO,“返回值优化”
,但从c++17
开始,返回值优化是强制性的,不再视为复制省略。请看下面的链接
有关更多详细信息。
您是否怀疑它丢失了移动语义,还是怀疑它速度较慢?或者两者都有?请查看生成的代码。或者用随机字符串和measure运行每个函数几百万次。此外,返回
const
值与否并不重要。重要的是调用方将结果分配给什么。返回常量值没有意义。仅按值返回。返回常量值(与引用相反)是没有意义的。不要这样做。你的编译器甚至应该警告你。而且auto&&str=g()
不同于=f()
@Nikos Copy-elision不受cv-qualifications差异的影响。你确定吗?我无法想象一个编译器有足够的勇气(C++17之前)复制elide一些内部为const
但外部为非const
的东西。关于你的最后一段,你能再分享一些信息吗?听起来。。。可疑的。