5

C++ アプリケーションを作成するときは、通常、C++ 固有の言語機能に限定します。ほとんどの場合、これは可能な限り CRT の代わりに STL を使用することを意味します。

私にとって、STL は CRT を使用するよりもはるかに流動的で保守しやすいものです。次の点を考慮してください。

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

C ランタイムに相当するものは次のようになります。

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

個人的には、前者の例の方がはるかに見やすいと思います。何が起こっているのかがより明確になりました。コードの最初のパスを書くとき、私の最初のことは常に最も自然な方法でコードを書くことです。

私のチームが前者の例で懸念していることの 1 つは、動的割り当てです。文字列が静的であるか、すでに別の場所に割り当てられている場合、断片化を引き起こす可能性や、ここで無駄な割り当てを行うことは意味がないと主張しています。これに対する私の主張は、最初に最も自然な方法でコードを記述し、コードが問題を引き起こしていることが証明された後に戻って変更することです。

後者の例が気に入らないもう 1 つの理由は、C ライブラリを使用していることです。通常、C++ ではなく、読みにくく、エラーが発生しやすく、セキュリティ リスクが高いという理由だけで、どうしても避けています。

だから私の質問は、C ランタイムを避けるのは正しいですか? コーディングのこのステップで余分な割り当てを本当に気にする必要がありますか? このシナリオで、私が正しいか間違っているかを判断するのは難しいです。

4

5 に答える 5

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

このクラスを適切な場所で使用すると、パフォーマンスが大幅に向上することに気付きました。これは強力なツールです。注意が必要です。文字列リテラルはプログラムの存続期間中存続することが保証されているため、文字列リテラルで最も役立つことがわかりました。もう 1 つの優れた機能は、新しい文字列を作成せずに部分文字列を取得できることです。

余談ですが、これに似たクラスを標準ライブラリに追加するという提案があります。

于 2012-05-23T17:52:17.483 に答える
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 ??_C@_05COLMCDPH@Hello?$AA@

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

  0000a 48 8d 15 00 00
        00 00            lea     rdx, OFFSET FLAT:??_C@_05COLMCDPH@Hello?$AA@
  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 ??_C@_05COLMCDPH@Hello?$AA@+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 $LN123@main

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

  00047 48 8d 0d 00 00
        00 00            lea     rcx, OFFSET FLAT:??_C@_05IOIEDEHB@Yes?$CB?6?$AA@
  0004e e8 00 00 00 00   call    printf

; 11   : 
; 12   : }

目に見える単一のメモリ割り当てではありません!

于 2012-05-23T18:19:01.623 に答える
4

C++ または C を使用していますか? それらはまったく異なる考え方を持つまったく異なる言語です。

C++ の場合:

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

Cの場合:

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

両方を混ぜないでください。

于 2012-05-23T17:12:35.440 に答える
0

内部では、std::string::operator== は表向きは strcmp を呼び出しています。正直なところ、断片化が問題ではなく、stl のより読みやすい構文を利用したい場合は、stl を使用してください。パフォーマンスが問題で、コードをプロファイリングして、std::string 内部データの一定の割り当て/割り当て解除がホットスポット/ボトルネックであることがわかった場合は、そこで最適化してください。operator==() と 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) { ... }

次に、スタイルの混合について議論することができます。これは、どちらも operator== を使用すると明らかに明確になるためです。

于 2012-05-23T17:41:08.623 に答える
0

チームが C++ でコーディングしている場合は、C++ が提供するすべての機能を使用する必要があります。もちろん、C++ を適切に使用すると、メモリ割り当て (コンストラクタとデストラクタ) とより自然な構文 (==、+) に気を配ることができます。

OOP スタイルの方が遅いと思うかもしれません。ただし、ボトルネックが文字列操作であることを最初に測定する必要があります。ほとんどのシナリオではありそうにありません。時期尚早の最適化は諸悪の根源です。適切に設計された C++ クラスは、便利に記述された C コードに負けません。

質問に戻ると、ライブラリを混在させる最悪のバリアントです。C 文字列を OOP ライブラリに置き換えることはできますが、それでも昔ながらの IO ルーチンと数学を使用しています。

于 2012-05-23T18:38:48.367 に答える