返回函数本地的std :: string的最佳方法

Ton*_*ion 51 c++ return-value

在C++中,从函数返回函数local std :: string变量的最佳方法是什么?

std::string MyFunc()
{
    std::string mystring("test");
    return mystring;

}

std::string ret = MyFunc(); // ret has no value because mystring has already gone out of scope...???
Run Code Online (Sandbox Code Playgroud)

Chu*_*dad 70

不,那不是真的.即使mystring已经超出范围并被销毁,ret也有一个mystring的副本,因为函数MyFunc按值返回.

  • 当原始字符串对象超出范围并被破坏时,内部(堆)数据是否也会被删除?如果是这样的话,返回是否会进行深拷贝? (2认同)

Kir*_*rov 21

如果您的代码如下,则会出现问题:

std::string& MyFunc()
{
    std::string mystring("test");
    return mystring;
}
Run Code Online (Sandbox Code Playgroud)

所以,你写它的方式还可以.只有一个建议 - 如果你可以构造这样的字符串,我的意思是 - 你可以在一行中完成它,有时候这样做更好:

std::string MyFunc()
{
    return "test";
}
Run Code Online (Sandbox Code Playgroud)

或者如果它更"复杂",对于ex:

std::string MyFunct( const std::string& s1, 
                     const std::string& s2, 
                     const char* szOtherString )
{
    return std::string( "test1" ) + s1 + std::string( szOtherString ) + s2;
}
Run Code Online (Sandbox Code Playgroud)

这将为您的编译器提供更多优化的提示,因此它可以减少一个字符串副本(RVO).


typ*_*gic 19

之前的答案都没有包含这里的关键概念。这个概念就是移动语义。该类std::string具有move构造函数,这意味着它具有移动语义移动语义意味着对象不会在函数返回时复制到不同的位置,从而提供更快的函数执行时间。

尝试对返回的函数进行单步调试std::string,并检查即将返回的对象的内部结构。您将看到一个成员字段指针地址xxx。然后,检查std::string接收函数返回值的变量。您将在该对象中看到相同的指针地址xxx

这意味着女士们先生们,没有发生任何复制行为。这就是举动语义,上帝保佑美国!

  • 很好的答案...但实际上@daparic...美国与这篇文章到底有什么关系,更不用说StackOverflow [在全球软件开发人员使用的论坛上]? (3认同)

kiz*_*zx2 6

如上所述,复制了std :: string.因此,即使原始局部变量超出范围,调用者也会获得std :: string的副本.

我认为阅读RVO可以完全清除你的困惑.在这种情况下,它被准确地称为NRVO(命名为RVO),但精神是相同的.

额外阅读:使用RVO的问题在于它不是世界上最灵活的东西.C++ 0x的一个重要嗡嗡声是rvalue引用,它打算解决这个问题.


Mar*_*rst 5

你试过吗?返回时会复制该字符串.嗯,这是官方的路线,实际上副本可能已经优化了,但无论哪种方式都可以安全使用.

  • "在类的情况下......使用非平凡的构造函数,它无法被优化掉" - 哦,但它可以,而且通常是.试试这个:std :: string*sp; std :: string func(){std :: string s("bla"); sp =&s; 回归; } int main(){std :: string s = func(); if(sp ==&s)std :: cout <<"YAY"; 别人std :: cout <<"BOO"; } - 在我的编译器(VS)上打印YAY. (4认同)
  • PigBen写的当然会导致未定义的行为,但即使在定义的情况下,编译器有时也会对副本进行正确的删除.谷歌的RVO和NRVO. (2认同)