30

std :: stringとどう違うのですか?

4

7 に答える 7

120

「文字列」は実際には単なるcharsの配列です。nullで終了する文字列は、null文字が'\0'文字列の終わりを示す文字列です(必ずしも配列の終わりである必要はありません)。コード内のすべての文字列(二重引用符で区切られている"")は、コンパイラによって自動的にnullで終了します。

したがって、たとえば、はと"hi"同じ{'h', 'i', '\0'}です。

于 2010-01-10T14:10:56.367 に答える
50

ヌルで終了する文字列は、文字の連続したシーケンスであり、最後の文字列はすべてゼロのバイナリビットパターンを持っています。「通常の文字列」が何を意味するのかはわかりませんが、意味する場合はstd::string、aが連続しているstd::string必要はなく(C ++ 11まで)、ターミネータは必要ありません。また、std::stringの文字列データは常に、std::stringそれを含むオブジェクトによって割り当てられ、管理されます。nullで終了する文字列の場合、そのようなコンテナはありません。通常、裸のポインタを使用してそのような文字列を参照および管理します。

これらすべては、まともなC++の教科書で実際にカバーされているはずです-私はそれらの最高の1つであるAcceleratedC++を手に入れることをお勧めします。

于 2010-01-10T14:06:31.930 に答える
16

文字列を表す主な方法は2つあります。

1)最後にASCIIヌル(nul)文字0が付いた文字のシーケンス。ターミネーターを検索することで、その長さを知ることができます。これはnullで終了する文字列と呼ばれるか、nulで終了することもあります。

2)文字のシーケンスに加えて、長さを示す個別のフィールド(整数の長さ、または文字列の末尾へのポインタ)。

「通常の文字列」についてはよくわかりませんが、特定の言語について話すとき、「文字列」という単語はその言語の標準的な表現を意味するために使用されることがよくあります。したがって、Javaでは、java.lang.Stringはタイプ2の文字列であるため、「文字列」の意味です。Cでは、「文字列」はおそらくタイプ1文字列を意味します。標準は正確にするために非常に冗長ですが、人々は常に「明白な」ものを省略したいと考えています。

C ++では、残念ながら、両方のタイプが標準です。std ::stringはタイプ2文字列[*]ですが、Cから継承された標準ライブラリ関数はタイプ1文字列で動作します。

[*]実際、std :: stringは、多くの場合、個別の長さフィールドnulターミネータを持つ文字の配列として実装されます。これによりc_str()、文字列データをコピーしたり再割り当てしたりすることなく、関数を実装できます。長さフィールドを格納せずにstd::stringを実装することが合法であるかどうかをすぐに思い出せません。問題は、標準でどのような複雑さの保証が必要かということです。一般に、コンテナのsize()場合はO(1)にすることをお勧めしますが、実際にはそうする必要はありません。したがって、それが合法であるとしても、nul-terminatorを使用するだけのstd::stringの実装は驚くべきことです。

于 2010-01-10T14:18:09.210 に答える
8
'\0' 

コード0、ヌルターミネータ、ヌル文字、NULのASCII文字です。C言語では、文字列の終わりを示すために使用される予約文字として機能します。とりわけstrcpy、strlen、strcmpなどの多くの標準関数はこれに依存しています。それ以外の場合、NULがなかった場合は、文字列の終わりを通知する別の方法が使用されている必要があります。

これにより、文字列は1バイトのオーバーヘッドのみで任意の長さにすることができます。カウントを格納する代わりに、255の文字列長制限または1バイトを超えるオーバーヘッドが必要です。

ウィキペディアから

C ++ std::stringはこの他の規則に従い、そのデータは次のような構造で表されます_Rep

// _Rep: string representation
      //   Invariants:
      //   1. String really contains _M_length + 1 characters: due to 21.3.4
      //      must be kept null-terminated.
      //   2. _M_capacity >= _M_length
      //      Allocated memory is always (_M_capacity + 1) * sizeof(_CharT).
      //   3. _M_refcount has three states:
      //      -1: leaked, one reference, no ref-copies allowed, non-const.
      //       0: one reference, non-const.
      //     n>0: n + 1 references, operations require a lock, const.
      //   4. All fields==0 is an empty string, given the extra storage
      //      beyond-the-end for a null terminator; thus, the shared
      //      empty string representation needs no constructor.

      struct _Rep_base
      {
    size_type       _M_length;
    size_type       _M_capacity;
    _Atomic_word        _M_refcount;
      };

struct _Rep : _Rep_base
      {
    // Types:
    typedef typename _Alloc::template rebind<char>::other _Raw_bytes_alloc;

    // (Public) Data members:

    // The maximum number of individual char_type elements of an
    // individual string is determined by _S_max_size. This is the
    // value that will be returned by max_size().  (Whereas npos
    // is the maximum number of bytes the allocator can allocate.)
    // If one was to divvy up the theoretical largest size string,
    // with a terminating character and m _CharT elements, it'd
    // look like this:
    // npos = sizeof(_Rep) + (m * sizeof(_CharT)) + sizeof(_CharT)
    // Solving for m:
    // m = ((npos - sizeof(_Rep))/sizeof(CharT)) - 1
    // In addition, this implementation quarters this amount.
    static const size_type  _S_max_size;
    static const _CharT _S_terminal;

    // The following storage is init'd to 0 by the linker, resulting
        // (carefully) in an empty string with one reference.
        static size_type _S_empty_rep_storage[];

        static _Rep&
        _S_empty_rep()
        { 
      // NB: Mild hack to avoid strict-aliasing warnings.  Note that
      // _S_empty_rep_storage is never modified and the punning should
      // be reasonably safe in this case.
      void* __p = reinterpret_cast<void*>(&_S_empty_rep_storage);
      return *reinterpret_cast<_Rep*>(__p);
    }

        bool
    _M_is_leaked() const
        { return this->_M_refcount < 0; }

        bool
    _M_is_shared() const
        { return this->_M_refcount > 0; }

        void
    _M_set_leaked()
        { this->_M_refcount = -1; }

        void
    _M_set_sharable()
        { this->_M_refcount = 0; }

    void
    _M_set_length_and_sharable(size_type __n)
    {
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
      if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
        {
          this->_M_set_sharable();  // One reference.
          this->_M_length = __n;
          traits_type::assign(this->_M_refdata()[__n], _S_terminal);
          // grrr. (per 21.3.4)
          // You cannot leave those LWG people alone for a second.
        }
    }

    _CharT*
    _M_refdata() throw()
    { return reinterpret_cast<_CharT*>(this + 1); }

    _CharT*
    _M_grab(const _Alloc& __alloc1, const _Alloc& __alloc2)
    {
      return (!_M_is_leaked() && __alloc1 == __alloc2)
              ? _M_refcopy() : _M_clone(__alloc1);
    }

    // Create & Destroy
    static _Rep*
    _S_create(size_type, size_type, const _Alloc&);

    void
    _M_dispose(const _Alloc& __a)
    {
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
      if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
        if (__gnu_cxx::__exchange_and_add_dispatch(&this->_M_refcount,
                               -1) <= 0)
          _M_destroy(__a);
    }  // XXX MT

    void
    _M_destroy(const _Alloc&) throw();

    _CharT*
    _M_refcopy() throw()
    {
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
      if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
            __gnu_cxx::__atomic_add_dispatch(&this->_M_refcount, 1);
      return _M_refdata();
    }  // XXX MT

    _CharT*
    _M_clone(const _Alloc&, size_type __res = 0);
      };

実際のデータは次の方法で取得できます。

_Rep* _M_rep() const
      { return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); }

このコードスニペットは、basic_string.h私のマシン上にあるファイルからのものですusr/include/c++/4.4/bits/basic_string.h

ご覧のとおり、違いは重要です。

于 2013-08-04T00:55:03.613 に答える
3

nullで終了する文字列は、文字列の終わりがnull文字の出現によって定義されることを意味します(すべてのビットはゼロです)。

「その他の文字列」は、たとえば、独自の長さを格納する必要があります。

于 2010-01-10T14:09:10.283 に答える
1

nullで終了する文字列は、Cのネイティブ文字列形式です。たとえば、文字列リテラルはnullで終了する文字列として実装されます。その結果、多くのコード(最初はCランタイムライブラリ)は、文字列がnullで終了することを前提としています。

于 2010-01-10T14:11:04.230 に答える
0

ヌル終了文字列(c-string)は、charの配列であり、配列の最後の要素は0x0値です。std :: stringは、値の自動サイズ変更コンテナであるという点で、本質的にベクトルです。サイズ変更が必要な時期を知るためにサイズを追跡する必要があるため、ヌルターミネータは必要ありません。

正直なところ、私はstdよりもc-stringの方が好きです。基本的なライブラリには、コードと割り当てが最小限のアプリケーションが多く、そのために使いにくいものがあります。

于 2013-08-04T01:01:59.923 に答える