Ответ 1
Последний глупый, потому что он не использует инициализацию, когда это возможно.
Первые два полностью идентичны семантически (думайте о функции члена c_str()
), поэтому предпочитайте первую версию, потому что она самая прямая и идиоматическая и проще всего читать.
(Существовала бы семантическая разница, если std::string
имел конструктор по умолчанию constexpr
, но это не так. Тем не менее, возможно, что std::string()
отличается от std::string("")
, но я не знаю реализации, которые делают это, поскольку это, похоже, не имеет большого смысла. С другой стороны, популярные оптимизации небольших строк в настоящее время означают, что обе версии, вероятно, не будут выполнять динамическое распределение.)
Обновление. Как указывает @Jonathan, два конструктора строк, вероятно, будут выполнять другой код, и если это имеет значение для вас (хотя это действительно не так), вы можете рассмотреть четвертую версию:
: cstr ? cstr : std::string()
Как чтение, так и построение по умолчанию.
Второе обновление: но предпочитайте cstr ? cstr : ""
. Как вы можете видеть ниже, когда обе ветки называют один и тот же конструктор, это может быть реализовано очень эффективно с использованием условных ходов и ветвей. (Таким образом, две версии действительно генерируют другой код, но первый лучше.)
Для хихиканья я запустил обе версии через Clang 3.3, с -O3
, на x86_64, для struct foo;
, как ваш, и функцию foo bar(char const * p) { return p; }
:
Конструктор по умолчанию (std::string()
):
.cfi_offset r14, -16
mov R14, RSI
mov RBX, RDI
test R14, R14
je .LBB0_2
mov RDI, R14
call strlen
mov RDI, RBX
mov RSI, R14
mov RDX, RAX
call _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcm
jmp .LBB0_3
.LBB0_2:
xorps XMM0, XMM0
movups XMMWORD PTR [RBX], XMM0
mov QWORD PTR [RBX + 16], 0
.LBB0_3:
mov RAX, RBX
add RSP, 8
pop RBX
pop R14
ret
Конструктор пустой строки (""
):
.cfi_offset r14, -16
mov R14, RDI
mov EBX, .L.str
test RSI, RSI
cmovne RBX, RSI
mov RDI, RBX
call strlen
mov RDI, R14
mov RSI, RBX
mov RDX, RAX
call _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcm
mov RAX, R14
add RSP, 8
pop RBX
pop R14
ret
.L.str:
.zero 1
.size .L.str, 1
В моем случае было бы даже казаться, что ""
генерирует лучший код: обе версии вызывают strlen
, но версия с пустой строкой не использует никаких переходов, только условные перемещения (поскольку тот же самый конструктор вызывается, просто с двумя разными аргументами). Конечно, это совершенно бессмысленное, не переносное и непередаваемое наблюдение, но это просто показывает, что компилятор не всегда нуждается в такой же помощи, как вы могли бы подумать. Просто напишите код, который выглядит лучше всего.