C++ 返回常量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会降低移动构造效率,速度也会变慢

分配此方法的返回字符串是否为真:

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
的东西。关于你的最后一段,你能再分享一些信息吗?听起来。。。可疑的。