【问题标题】:"std::string" or "const std::string&" argument? (the argument is internally copied and modified)“std::string”还是“const std::string&”参数? (参数在内部被复制和修改)
【发布时间】:2013-06-10 13:01:43
【问题描述】:

考虑这段代码:

void doSomethingWithString(string& mString)
{
     // mString gets modified in here
}

string getCopy1(const string& mString) 
{ 
    string result{mString}; doSomethingWithString(result); return result; 
}

string getCopy2(string mString) 
{ 
    doSomethingWithString(mString); return mString; 
}

getCopy1getCopy2 之间是什么:

  • 清楚地表明传递的字符串不会被修改
  • 清楚地表明用户会得到一个新的字符串返回
  • 更快/编译器可以更好地优化(启用 C++11,考虑移动语义)

?

【问题讨论】:

  • 不确定问题是什么。你不放弃答案吗?
  • @KonradRudolph 问题是列出的三个点。基本上,getCopy1 和 getCopy2 都做同样的事情 - 哪个更快,更具表现力?
  • 无耻插件:见stackoverflow.com/questions/16944715/…——我犹豫是否将问题标记为重复,因为另一个问题专门关于构造函数(以及从参数初始化成员变量)并且还有其他细微差别,但大局是一样的。
  • 如果您要制作副本无论如何,请在参数中进行,所以getCopy2 是。
  • @Vee:不,在您的情况下传递值更好。看看答案,他们会解释。

标签: c++ string c++11 reference parameter-passing


【解决方案1】:

这两个版本都清楚地表明没有意图修改传入的值。

getCopy2 在将右值作为参数传递的情况下效率更高。在这种情况下,不需要进行复制,因为参数将被移动而不是复制,并且您没有进行内部复制。对于getCopy1,您始终强制至少制作一份副本。如果将左值作为参数传递,则需要进行移动而不是创建引用。哪个更高效取决于编译器和字符串实现的很多细节,但移动的速度应该与创建引用的速度相当。

我看不出返回值有什么不同。

【讨论】:

  • 我怀疑一个好的优化器可能会解决这个问题,但我同意。 getCopy2 在风格上都更好,更多的优化器会更好地处理这种情况。
  • 谢谢,我现在明白了。我在可能的情况下使用“getCopy2-style”参数传递改进了我的库。 (github.com/SuperV1234/SSVUtils/commit/…)
【解决方案2】:

getCopy1 和 getCopy2 之间是什么:

  • 清楚地表明传递的字符串不会被修改

两者:首先,因为虽然它需要一个引用,但引用是const;其次,因为它会创建自己的副本。

  • 清楚地表明用户会得到一个新的字符串返回

两者:它们都返回一个字符串实例;

  • 更快/编译器可以更好地优化(启用 C++11,考虑移动语义)

第二个更好用:如果你正在制作输入参数的副本,最好在参数本身中进行(最好让编译器制作副本,随叫随到);这也更好,因为在右值引用的情况下,没有额外的复制。

【讨论】:

    【解决方案3】:

    在 Linux Mint x64 上使用 G++ 4.8.1 进行了一些测试。 标志:-std=c++11 -O3 -DNDEBUG

    void doSomethingWithString(string& mString) { mString[0] = 'f'; }
    
    string getCopy1(const string& mString)
    {
        string result{mString}; doSomethingWithString(result); return result;
    }
    
    string getCopy2(string mString)
    {
        doSomethingWithString(mString); return mString;
    }
    
    int main()
    {
        string s{"132958fdgefi9obm3890g54"};
        string t{""};
    
        {
            startBenchmark();
            for(int i{0}; i < 20000000; ++i) t = getCopy1(s);
            log(endBenchmark(), "getCopy1 variable");
        }
        {
            startBenchmark();
            for(int i{0}; i < 20000000; ++i) t = getCopy1("abcsd");
            log(endBenchmark(), "getCopy1 literal");
        }
    
        {
            startBenchmark();
            for(int i{0}; i < 20000000; ++i) t = getCopy2(s);
            log(endBenchmark(), "getCopy2 variable");
        }
        {
            startBenchmark();
            for(int i{0}; i < 20000000; ++i) t = getCopy2("abcsd");
            log(endBenchmark(), "getCopy2 literal");
        }
    
        return 0;
    }
    

    输出:

    [getCopy1 variable] 1236 ms
    [getCopy1 literal] 1845 ms
    [getCopy2 variable] 993 ms
    [getCopy2 literal] 857 ms
    

    结论:

    getCopy2 更快,尤其是右值(文字字符串)。

    【讨论】:

      【解决方案4】:

      getCopy2 通常可以得到更好的优化。这在"Want Speed? Pass by Value."中得到了巧妙的解释

      【讨论】:

        猜你喜欢
        • 2012-12-27
        • 1970-01-01
        • 2023-03-26
        • 1970-01-01
        • 1970-01-01
        • 2014-11-19
        • 1970-01-01
        • 2020-02-06
        • 2014-02-19
        相关资源
        最近更新 更多