2012-05-23 2 views
4

При написании приложения на C++ я обычно ограничиваю себя специальными языковыми функциями на C++. В основном это означает использование STL вместо CRT, где это возможно.Избегайте CRT

Для меня STL является гораздо более жидким и ремонтопригодным, чем использование ЭЛТ. Рассмотрим следующий пример:

std::string str("Hello"); 
if(str == "Hello") { ... } 

эквивалент C-время выполнения будет:

char const* str = "Hello"; 
if(strcmp(str, "Hello") == 0) { ... } 

Лично я считаю, бывший пример гораздо проще смотреть. Мне просто понятно, что происходит. Когда я пишу первый проход моего кода, первое, что на моей шахте всегда - писать код самым естественным образом.

Одна из проблем, которые испытывает моя команда с прежним примером, - это динамическое распределение. Если строка статична ИЛИ уже выделена в другом месте, они утверждают, что нет смысла потенциально вызывать фрагментацию или иметь расточительное распределение здесь. Мой аргумент против этого состоит в том, чтобы сначала написать код наиболее естественным образом, а затем вернуться и изменить его после получения доказательства того, что код вызывает проблему.

Другая причина, по которой мне не нравится последний пример, заключается в том, что он использует библиотеку C. Как правило, я избегаю этого любой ценой просто потому, что это не C++, он менее читабельный и подвержен большей подверженности ошибкам и представляет собой скорее риск для безопасности.

Итак, мой вопрос: правильно ли я избегаю этого? Runtime? Должен ли я действительно заботиться о дополнительном распределении на этом этапе кодирования? Мне трудно сказать, прав я или нет в этом сценарии.

+1

С технической точки зрения библиотека C ** является ** C++. –

+0

Вы уже сами даете несколько хороших и обоснованных аргументов. –

+1

Если вы хотите неизменную строку времени компиляции, используйте 'const char (&) [N]', во всех остальных случаях используйте 'std :: string'. –

ответ

5

Я чувствую, что мой комментарий о llvm::StringRef проигнорирован, поэтому я сделаю из этого ответ.

llvm::StringRef str("Hello"); 

Это по существу устанавливает указатель, вызывает strlen, а затем устанавливает другой указатель. Нет распределения.

if (str == "Hello") { do_something(); } 

Считываемое и все еще не выделенное. Он также работает с std::string.

std::string str("Hello"); 
llvm::StringRef stref(str); 

Вы должны быть осторожны с этим, хотя, потому что, если строка будет уничтожен или перераспределены, то StringRef становится недействительным.

if (str == stref) { do_something(); } 

Я заметил весьма существенные преимущества при использовании этого класса в соответствующих местах. Это мощный инструмент, вам просто нужно быть осторожным с ним. Я нахожу, что это наиболее полезно для строковых литералов, так как они гарантированно сохраняются на протяжении всей жизни программы. Еще одна интересная особенность заключается в том, что вы можете получить подстроки, не создавая новую строку.

В стороне, есть предложение добавить класс, подобный этому, в стандартную библиотеку.

+0

Предложение - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3334.html, если кому-то еще интересно. Я не знал, что это происходит; это хорошие новости. std: строка всегда была немного бледной. – mrec

4

Вы делаете C++ или C? Это совершенно разные языки с совершенно разными способами мышления.

Если C++:

std::string str("Hello"); 
if(str == "Hello") { ... } 

Если C:

char const* str = "Hello"; 
if(strcmp(str, "Hello") == 0) { ... } 

Не смешивать оба.

+0

Было ли ваше мнение одинаковым, если это было сделано в приложении с длительным сроком службы (сервером), которое уже имеет проблемы с памятью/фрагментацией? –

+0

@RobertDailey Конечно. Проблемы фрагментации памяти происходят не из стиля вашего кода. –

+0

Почему бы не смешать это? Очевидно, что 'std :: string (" ... ")' производит гораздо больше кода и работает намного медленнее, чем «C-вариант». Итак, в C++, когда у вас есть постоянная строка времени компиляции, почему бы не использовать код «C-style»? – valdo

0

Под капотом std :: string :: operator == якобы вызывает strcmp. Честно говоря, если фрагментация не является проблемой для вас, и вам нравится использовать более читаемый синтаксис stl, пойдите для него и используйте stl. Если производительность является проблемой, и вы просматриваете код, и вы видите, что постоянное распределение/освобождение внутренних данных std :: string является точкой доступа/узким местом, оптимизируйте его. Если вам не нравится противоречивый стиль кодирования оператор смешивания ==() и STRCMP, написать что-то вроде этого:

inline bool str_eq(const char* const lhs, const char* const rhs) 
{ 
    return strcmp(lhs, rhs) == 0; 
} 
inline bool str_eq(const std::string& lhs, const char* const rhs) 
{ 
    return str_eq(lhs.c_str(), rhs); 
} 
inline bool str_eq(const char* const lhs, const std::string& rhs) 
{ 
    return str_eq(lhs, rhs.c_str()); 
} 
inline bool str_eq(const std::string& lhs, const std::string& rhs) 
{ 
    return lhs == rhs; 
} 

Это не должно быть действительно религиозный разговор. Оба работают одинаково. Теперь, если вы видите кого-то писать

std::string str("Hello"); 
if(strcmp(str.c_str(), "Hello") == 0) { ... } 

или

std::string str("Hello"); 
if(str.compare("Hello") == 0) { ... } 

, то вы можете иметь дебаты о смешивании стилей, потому что и те, очевидно, будет яснее, используя оператор ==

4

Использование компилятора, который реализует Small String Optimization, я получаю этот результат:

main PROC      ; COMDAT 

; 6 : { 

$LN124: 
    00000 48 83 ec 48  sub rsp, 72   ; 00000048H 

; 7 : std::string str("Hello"); 

    00004 8b 05 00 00 00 
     00    mov eax, DWORD PTR [email protected][email protected][email protected] 

; 8 : 
; 9 : if(str == "Hello") 

    0000a 48 8d 15 00 00 
     00 00   lea  rdx, OFFSET FLAT:[email protected][email protected][email protected] 
    00011 48 8d 4c 24 20 lea  rcx, QWORD PTR str$[rsp] 
    00016 89 44 24 20  mov  DWORD PTR str$[rsp], eax 
    0001a 0f b6 05 04 00 
     00 00   movzx eax, BYTE PTR [email protected][email protected][email protected]+4 
    00021 41 b8 05 00 00 
     00    mov  r8d, 5 
    00027 c6 44 24 37 00 mov  BYTE PTR str$[rsp+23], 0 
    0002c 48 c7 44 24 38 
     05 00 00 00  mov  QWORD PTR str$[rsp+24], 5 
    00035 c6 44 24 25 00 mov  BYTE PTR str$[rsp+5], 0 
    0003a 88 44 24 24  mov  BYTE PTR str$[rsp+4], al 
    0003e e8 00 00 00 00 call memcmp 
    00043 85 c0   test eax, eax 
    00045 75 1d   jne  SHORT [email protected] 

; 10 : { printf("Yes!\n"); } 

    00047 48 8d 0d 00 00 
     00 00   lea  rcx, OFFSET FLAT:[email protected][email protected][email protected] 
    0004e e8 00 00 00 00 call printf 

; 11 : 
; 12 : } 

Не один выделения памяти в поле зрения!

+0

Поскольку это оптимизация (и только для небольших строк, как говорится в названии), это не должно быть фактором в вашем решении. –

+0

По крайней мере, это означает, что пример в вопросе не является реальной проблемой, поэтому одна проблема меньше беспокоиться. –

+0

Это связано с тем, что в некоторых версиях STL реализация 'std :: string' реализована как гибрид буфера фиксированного размера (обычно длиной 32 символа), ** и ** указатель на (опционально) выделенное хранилище. Попробуйте запустить пример с более длинной строкой. – valdo

0

Если ваша команда кодирует на C++, вы должны использовать все функции, которые она предлагает. Конечно, C++ должным образом использует заботу о распределении памяти (конструкторы и деструкторы) и более естественный синтаксис (для ==, +).

Вы можете подумать, что стиль ООП может быть медленнее. Но сначала вы должны измерить, что узкое место - это строковые операции. Это маловероятно для большинства сценариев. Преждевременная оптимизация - корень всего зла. Правильно разработанные классы C++ не потеряют удобного письменного кода C.

Возвращаясь к вашему вопросу, наихудший вариант для смешивания библиотек. Вы можете заменить строку C библиотекой ООП, но все же использовать программы и математические процедуры старой школы.

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

  • Нет связанных вопросов^_^