C ++のchar * vs std :: string [クローズ]


81

C ++でsの配列を管理するためstd::stringに、いつ使用する必要があり、いつ使用する必要がありますか?char*char

char*パフォーマンス(速度)が重要であり、メモリ管理のためにリスクの高いビジネスの一部を受け入れても構わないと思っている場合は、使用する必要があるようです。

考慮すべき他のシナリオはありますか?

回答:


56

std :: stringが大きい場合は、コピーを避けるために参照によって渡すか、インスタンスへのポインターを渡すことができるため、charポインターを使用しても実際の利点はわかりません。

私は実際のテキストである多かれ少なかれすべてにstd :: string / wstringを使用します。char *ただし、他のタイプのデータには便利であり、必要に応じて割り当てが解除されることを確認できます。それ以外の場合は、std :: vectorが最適です。

これらすべてにはおそらく例外があります。


8
2つの前にパフォーマンスの違いはありますか?
vtd-xml-author 2010

3
@ vtd-xml-作成者:多分いくつか。ストレートにchar *はほとんどオーバーヘッドがありません。正確にどのようなオーバーヘッドstd::stringがあるのか​​はわかりませんが、実装に依存する可能性があります。オーバーヘッドが裸のcharポインターのオーバーヘッドよりもはるかに大きくなることはほとんど期待できません。私は規格のコピーを所有していないので、規格によって行われた保証について詳しく説明することはできません。パフォーマンスの違いは、実行する操作によって異なる可能性があります。std::string::size文字データの横にサイズを格納できるため、よりも高速になりstrlenます。
スカルメデル2010

2
非テキストデータにstd :: stringを使用しないのはなぜですか?それらはヌル終了ではないので、そこに必要なものを何でも保存できるはずです。
ケーシーロダーマー2012年

1
@rodarmor文字列はnullで終了する文字列用に設計されているため、少し危険です、必要なものは何でも保存できます。の代わりに、たとえばappend(const string&)、バイナリセーフ操作のみを使用するように注意する必要があります。append(const char*, size_t)operator+=()
ボーイシー2012年

6
本気ですか?多くの操作でchar *がnullで終了する文字列であると想定することは知っていますが、std :: stringにnullが含まれていないと想定する操作は考えられません。
ケーシーロダーマー2012年

58

私の見解は次のとおりです。

  • 「C」コードを呼び出さない場合は、char *を使用しないでください。
  • 常にstd :: stringを使用してください:より簡単で、よりフレンドリーで、最適化されており、標準であり、バグが発生するのを防ぎ、チェックされ、動作することが証明されています。

13

生の文字列の使用法

はい、時々あなたは本当にこれを行うことができます。const char *、スタックに割り当てられたchar配列、および文字列リテラルを使用する場合、メモリ割り当てがまったくないように行うことができます。

このようなコードを書くには、文字列やベクトルを使用するよりも多くの考えと注意が必要ですが、適切な手法を使用すれば実行できます。適切な手法を使用すれば、コードは安全ですが、char []にコピーするときは、コピーする文字列の長さを保証するか、特大の文字列を適切にチェックして処理する必要があります。そうしないことが、strcpyファミリーの関数に安全ではないという評判を与えた理由です。

テンプレートが安全なcharバッファの作成にどのように役立つか

char []バッファーの安全性に関しては、テンプレートがバッファーサイズを処理するためのカプセル化を作成できるため、テンプレートが役立ちます。このようなテンプレートは、strcpyの安全な代替品を提供するために、たとえばMicrosoftによって実装されています。ここでの例は私自身のコードから抽出されたものであり、実際のコードにはさらに多くのメソッドがありますが、これは基本的な考え方を伝えるのに十分なはずです。

template <int Size>
class BString
{
  char _data[Size];

  public:
  BString()
  {
    _data[0]=0;
    // note: last character will always stay zero
    // if not, overflow occurred
    // all constructors should contain last element initialization
    // so that it can be verified during destruction
    _data[Size-1]=0;
  }
  const BString &operator = (const char *src)
  {
    strncpy(_data,src,Size-1);
    return *this;
  }

  operator const char *() const {return _data;}
};

//! overloads that make conversion of C code easier 
template <int Size>
inline const BString<Size> & strcpy(BString<Size> &dst, const char *src)
{
  return dst = src;
}

1
「constchar *、スタックに割り当てられたchar配列、および文字列リテラルを使用する場合、メモリ割り当てがまったくないような方法でそれを行うことができます。」の+1 人々は、スタックの「割り当て」がヒープよりもはるかに速いことを忘れています。
NoSenseEtAl 2011年

char*文字列は常にスタック上にあるとは限りません。char *str = (char*)malloc(1024); str[1024] = 0;
コールジョンソン

@ColeJohnson私はそれを主張していません。つまり、文字列をスタック割り当てする場合は、std :: stringではなく文字列リテラルと組み合わせてconstchar *を使用する必要があるということです。
スマ

9

使用char*しなければならない場合と使用しない場合の1つstd::stringは、静的文字列定数が必要な場合です。その理由は、モジュールが静的変数を初期化する順序を制御できず、別のモジュールの別のグローバルオブジェクトが、初期化される前に文字列を参照する可能性があるためです。http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Static_and_Global_Variables

std::string 長所:

  • あなたのためにメモリを管理します(文字列は大きくなる可能性があり、実装はより大きなバッファを割り当てます)
  • 高レベルのプログラミングインターフェイスは、STLの他の部分とうまく連携します。

std::string短所:-2つの異なるSTL文字列インスタンスが同じ基になるバッファを共有することはできません。したがって、値を渡すと、常に新しいコピーが取得されます。-パフォーマンスの低下はありますが、要件が特別でない限り、無視できると思います。


実際、STL実装はstd :: stringのコピーオンライトセマンティクスを実装することが多いため、値で渡すことはそれほどコストがかかりません。それでも、それに依存しない方が良いですし、とにかくconstへの参照を渡す方が一般的には良いです。

1
一部のstd :: string実装は、COW実装をあきらめました。さらに、標準と互換性のある(POSIX)スレッドセーフクラスを提供しているように見えるほど簡単ではありません。groups.google.fr/group/ifi.test.boa/browse_frm/thread/…またはgroups.google.fr/group/comp.programming.threads/browse_frm/…を
Luc

8

char*次の場合に使用することを検討する必要があります。

  • この配列はパラメータで渡されます。
  • 配列の最大サイズを事前に知っています(知っているか、強制します)。
  • この配列では変換を行いません。

実際、C ++では、char*オプション、ファイル名などとして、固定された小さな単語によく使用されます...


3
配列は渡されません。配列へのポインタです。それがポインタです—オブジェクトへのポインタです。
コールジョンソン

5

c ++ std :: stringを使用する場合:

  • 全体として、文字列はchar *よりも安全です。通常、char *で処理を行う場合は、処理が正しいことを確認する必要があります。文字列クラスでは、これがすべて実行されます。
  • 通常、char *を使用する場合は、割り当てたメモリを解放する必要があります。破棄されると内部バッファが解放されるため、文字列で解放する必要はありません。
  • 文字列はC ++文字列ストリームでうまく機能し、フォーマットされたIOは非常に簡単です。

char *を使用する場合

  • char *を使用すると、舞台裏で何が起こっているかをより細かく制御できます。つまり、必要に応じてパフォーマンスを調整できます。

3

ライブラリーを作成する場合は、パラメーターとして(const)char *を使用してください。std :: stringの実装は、コンパイラによって異なります。


C ++でライブラリを作成している場合、心配する必要があるのはstd :: stringのレイアウトだけではありません。2つの実装の間には多くの潜在的な非互換性があります。C ++でライブラリを使用するのは、ソースで利用できる場合、または使用しているコンパイラとまったく同じようにコンパイルされている場合のみです。Cライブラリは通常、より移植性がありますが、その場合はとにかくstd :: stringがありません。
David Thornley

std :: stringだけが問題ではないことは事実ですが、「C ++でライブラリを使用するのは、ソースで利用できる場合、または使用しているコンパイラ用にコンパイルされている場合のみ」と結論付けるには少し多すぎます。さまざまなコンパイラ(COMなど)で正常に動作するコンポーネントシステムがあり、C ++で内部的に記述されたライブラリ(Win32 APIなど)にCインターフェイスを公開することができます
Nemanja Trifunovic

2

Cライブラリを使用する場合は、C文字列を処理する必要があります。APIをCに公開する場合も同様です。


2

std :: string(egなどfind)に対するほとんどの操作は可能な限り最適化されることが期待できるため、少なくとも純粋なCの対応物と同様に実行される可能性があります。

std :: stringイテレータは、基になるchar配列へのポインタにマップされることがよくあることにも注意してください。したがって、イテレータの上で考案したアルゴリズムは、パフォーマンスの点でchar *の上にある同じアルゴリズムと本質的に同じです。

注意すべき点は次のとおりです。たとえば、operator[]ほとんどのSTL実装は境界チェックを実行しないため、これを基になる文字配列に対する同じ操作に変換する必要があります。AFAIK STLPortはオプションで境界チェックを実行できます。その時点で、この演算子は少し遅くなります。

では、std :: stringを使用すると何が得られますか?手動のメモリ管理から解放されます。アレイのサイズ変更が簡単になり、通常、メモリの解放について考える必要が少なくなります。

文字列のサイズを変更するときにパフォーマンスが心配reserveな場合は、便利な関数があります。


1

テキストなどで文字の配列を使用している場合は、std :: stringをより柔軟で使いやすく使用してください。データストレージのような他の目的でそれを使用する場合は?配列を使用する(ベクトルを優先する)


1

パフォーマンスが重要な場合でも、より適切に使用vector<char>できます。事前にメモリを割り当てることができ(reserve()メソッド)、メモリリークを回避するのに役立ちます。vector :: operator []を使用するとオーバーヘッドが発生しますが、いつでもバッファのアドレスを抽出して、char *の場合とまったく同じようにインデックスを付けることができます。


しかし、ある種の典型的な文字列機能を使用し、ストレージのポリシーを指定するオプションがあると便利です。それについては私の答えのリンクを参照してください。
匿名

それは本当ではありません。ベクトルが連続したメモリ空間に割り当てられることを考慮すると、前のチャンクのコピーを意味するため、再割り当て(ベクトルサイズを増やすため)はまったく効率的ではありません。
ジェローム・

文字列の代わりにchar *の代わりにベクトルを使用しているため、私はあなたの応答を誤解しました...この場合は同意します。
–Jérôme

operator []の使用にオーバーヘッドがあってはなりません。たとえば、stackoverflow.com
questions / 381621 /…を

-1

AFAIKの内部では、ほとんどのstd :: stringは、文字列が参照によって渡されない場合でも、オーバーヘッドを回避するために、コピーオンライト、参照カウントセマンティクスを実装しています。


5
コピーオンライトはマルチスレッド環境で深刻なスケーラビリティの問題を引き起こすため、これはもはや真実ではありません。
スマ

少なくともGCCによるSTLの実装には当てはまります。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.