简体   繁体   中英

“std::string” or “const std::string&” argument? (the argument is internally copied and modified)

Consider this code:

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; 
}

Between getCopy1 and getCopy2 , what one:

  • Clearly shows that the passed string isn't going to get modified
  • Clearly shows that the user will get a new string returned
  • Is faster / can be better optimized by the compiler (C++11 enabled, consider move semantics)

?

Either version clearly shows there is no intent to modify the value that is passed in.

getCopy2 is more efficient in the case where an rvalue is being passed as the parameter. In that case, no copy needs to be done, since the parameter will be moved instead of copied, and you are doing no internal copying. For getCopy1 , you always force at least one copy to be made. If an lvalue is being passed as the parameter, then a move needs to be done instead of creating a reference. Which is more efficient depends on a lot of details of the compiler and the string implementation, but the speed of the move should be comparable to the speed of creating a reference.

I don't see any difference as far as the return value.

Between getCopy1 and getCopy2, what one:

  • Clearly shows that the passed string isn't going to get modified

Both: first, because although it takes a reference, the reference is const ; second, because it creates it's own copy.

  • Clearly shows that the user will get a new string returned

Both: they both return a string instance;

  • Is faster / can be better optimized by the compiler (C++11 enabled, consider move semantics)

The second is better to use: if you are making a copy of the input parameter, better do it in the parameter itself (better let the compiler make the copy, on call); It is also better because in the case of a rvalue reference, there is no extra copy done.

Ran some tests, with G++ 4.8.1 on Linux Mint x64. Flags: -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;
}

Output:

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

Conclusion:

getCopy2 is faster, especially with rvalues (literal strings).

getCopy2 can be often better optimized. This is neatly explained in "Want Speed? Pass by Value."

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM