#c #string #copy-constructor #assignment-operator
#c #строка #копировать-конструктор #оператор присваивания
Вопрос:
Какой код лучше использовать: для инициализации строки?
bool flag = /*function call...*/
string str = "abc";
if(flag)
str = "bcd";
Или
string str;
if(flag)
str = "bcd";
else
str = "abc";
Или
string str("abc");
if(flag)
str = "bcd";
Заранее спасибо.
Комментарии:
1. Этот вопрос лучше подходит для codereview.stackexchange.com
2. @MarkusDeibel Нет, он был бы закрыт, поскольку там отсутствует контекст .
3. Я полагаю, вы хотите сравнить это. Я подозреваю, что результаты будут другими, если вы используете строки по 40 символов вместо 3 символов
4.
string str = flag ? "bcd" : "abc";
Ответ №1:
Это микрооптимизация, которой вам не следует заниматься. Программа на C — это не описание сборки в удобочитаемом формате. Это высокоуровневое описание поведения, которое должна иметь ваша программа. Задача компилятора — создать сборку, которая демонстрирует указанное нами поведение.
Вы не указали, как вы используете результирующую строку, но если я сделаю несколько предположений и превращу ваш код в небольшие функции…
#include <string>
std::string foo1(bool flag) {
std::string str = "abc";
if(flag)
str = "bcd";
return str;
}
std::string foo2(bool flag) {
std::string str;
if(flag)
str = "bcd";
else
str = "abc";
return str;
}
std::string foo3(bool flag) {
std::string str("abc");
if(flag)
str = "bcd";
return str;
}
.. Clang 8.0 создаст практически эквивалентную сборку для трех случаев (и особенно для foo1
и foo3
)1. Вы можете увидеть это на Godbolt.
Что неудивительно, поскольку наблюдаемое поведение, которое диктуют ваши три фрагмента, одинаково и не зависит от того, какой фрагмент вы выбрали. Так что не зацикливайтесь на микрооптимизации. Остановитесь на описании оптимального поведения в большем масштабе.
1 — Ну, в есть заметная ветвь foo2
, но код, который будет выполняться во время выполнения, все равно всегда будет одним из потенциальных выделений и копией содержимого строки. Здесь могут быть некоторые затраты на неправильное предсказание ветвей, но если это не в действительно узком цикле, я бы не считал, что это стоит рассматривать. Более того, использование std::string
в таком цикле само по себе может показаться сомнительным.
Комментарии:
1. Тем не менее, это не та же сборка для случая 2. Если вы внимательно посмотрите, есть 2 вызова
string::replace
в случае 2 (по одному для каждой ветви). Также эффект производительности будет другим, если строка превысит размер буфера оптимизации коротких строк.2. @rustyx — Возможно, я неправильно подчеркнул. Я имел в виду, что «в значительной степени» должно быть более заметным. Я полагаю, что существуют две ветви, потому что это количество инструкций, которые нужно будет сбросить при неправильном прогнозировании ветвей.
3. @rustyx — Учитывая, что когда-либо будет выполняться только одна ветвь, SOO или нет, я не думаю, что ветвление заслуживает большего, чем сноска об эффективности, если вообще.
Ответ №2:
Способ C заключается в использовании инициализации:
bool flag = foo();
string str { flag ? "bcd" : "abc" };
flag
определяет, какой строковый литерал используется при вызове std::string::string(const char*)
. Но есть один вызов, создается один строковый объект и нет назначения.
[редактировать] Перевернул строковые литералы. В C , как для if
конструкции, так и для ?:
конструкта, «истинный» регистр идет первым, а затем «ложный» регистр последним. Но вопрос изменил их местами, «abc» появился первым для flag==false
случая.