2013-06-10 2 views
1

Рассмотрим этот код:"std :: string" или "const std :: string &" аргумент? (Аргумент внутренне скопирована и изменена)

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

Между getCopy1 и getCopy2, чем одно:

  • ясно показывает, что переданная строка не собирается модифицируются
  • Очевидно, что пользователь получит новую строку, возвращаемую
  • Быстрее/может быть лучше оптимизировано компилятором (включен C++ 11, рассмотрим семантику перемещения)

?

+0

Не знаете, в чем вопрос. Вы не согласны с ответом? –

+0

@ KonradRudolph Вопросы - это три перечисленные точки. В принципе, и getCopy1, и getCopy2 делают то же самое - что быстрее и выразительнее? –

+0

Бесстыдный штекер: см. Http://stackoverflow.com/questions/16944715/constructor-parameter-style/ - Я смущаюсь отмечать вопрос как дублирующийся, потому что другой конкретно посвящен конструкторам (и инициализации переменных-членов из параметра) и есть другие незначительные отличия, но большая картина такая же. – syam

ответ

2

Ran несколько тестов, с G ++ 4.8.1 в Linux Mint x64. Флаги: -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 быстрее, особенно с rvalues ​​(текстовые строки).

4

Либо версия ясно показывает, что нет намерения, чтобы изменить значение, которое передается в.

getCopy2 является более эффективным в том случае, когда Rvalue в настоящее время передается в качестве параметра. В этом случае копирование не требуется, поскольку параметр будет перемещен, а не скопирован, и вы не выполняете внутреннего копирования. Для getCopy1 вы всегда вынуждаете как минимум одну копию. Если в качестве параметра передается значение l, то вместо создания ссылки необходимо выполнить перемещение. Что более эффективно, зависит от множества деталей компилятора и строковой реализации, но скорость перемещения должна быть сопоставима со скоростью создания ссылки.

Я не вижу никакой разницы в отношении возвращаемого значения.

+0

Я подозреваю, что хороший оптимизатор может это исправить, но я согласен. getCopy2 лучше, и стилистически, и больше оптимизаторов лучше справятся с этим делом. – ChrisCM

+0

Спасибо, я понимаю сейчас. Я улучшил свою библиотеку, используя, по возможности, аргумент «getCopy2-style». (Https://github.com/SuperV1234/SSVUtils/commit/6f142392f9409c99d846a6ba3e7dbc2c861dccd2) –

3

Между getCopy1 и getCopy2, чем один:

  • ясно показывает, что переданная строка не собирается модифицируются

Оба: первый, потому что, хотя это занимает ссылка, ссылка const; во-вторых, потому что он создает свою собственную копию.

  • ясно показывает, что пользователь получит новый возвращаемая строка

Оба: они оба возвращают экземпляр строки;

  • Быстрее/может быть лучше оптимизирована компилятором (C++ 11 включен, рассмотрим движение семантики)

Второй лучше использовать: если вы делаете копию входного параметра, лучше сделайте это в самом параметре (лучше пусть компилятор сделает копию, по вызову); Это также лучше, потому что в случае ссылки на rvalue нет дополнительной копии.

Смежные вопросы