6

私は簡単なプログラムを持っています:

#include <iostream>
#include <string>
#include <string.h>

using namespace std;

string read0() {
    int length = 4;

    char *cstr = new char[length];

    string str(cstr);

    delete[] cstr;

    return str;
}

string read1() {
    int length = 4;

    char cstr[length];

    memset(cstr, '-', 4);

    string str(cstr);

   return str;
}

string read2() {
    const char* cstr = "abcd";

    string str(cstr);

    return str;
}

上記の 3 つの関数すべてで、文字列を作成するために、 they call basic_string( const CharT* s, const Allocator& alloc = Allocator(). valgrind/massif を使用してヒープの使用状況を確認すると、関数 read0 は (からnew) 4 バイトしか使用しませんが、read1 と read2 は両方とも 29 バイトを使用します。

以下は、massif の詳細な出力です。

read0 の場合:

16.67% (4B) (ヒープ割り当て関数) malloc/new/new[]、--alloc-fns など

->16.67% (4B) 0x400A0B: read0() (main.cpp:10)

->16.67% (4B) 0x400BC8: メイン (main.cpp:40)

read1 と read2 の場合:

72.50% (29B) (ヒープ割り当て関数) malloc/new/new[]、--alloc-fns など

->72.50% (29B) 0x4EE93B7: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator const&) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0 内) .17)

->72.50% (29B) 0x4EEAD93: char* std::string::_S_construct(char const*, char const*, std::allocator const&, std::forward_iterator_tag) (/usr/lib/x86_64-linux-gnu 内) /libstdc++.so.6.0.17)

->72.50% (29B) 0x4EEAE71: std::basic_string, std::allocator >::basic_string(char const*, std::allocator const&) (/usr/lib/x86_64-linux-gnu/libstdc++.so 内) 6.0.17)

->72.50% (29B) 0x400B81: read2() (main.cpp:34)

->72.50% (29B) 0x400BC8: メイン (main.cpp:40)

この違いの原因は何ですか?

4

2 に答える 2

8

私が間違っていたら誰かが私を訂正してください、しかし私はこれがなぜであるかを知っていると思います。

read0、あなたはします:

char *cstr = new char[length];
string str(cstr);

初期化はまったく行わないcstrため、未定義である可能性があります。文字列コンストラクターは、nullで終了するc文字列を受け取り、それをnullターミネーターまでコピーします。それは最初の要素で見つかると思うので、おそらく4バイトを占めるそのような文字列を指すポインタをコピーするだけです。

あなたread1も似ていると思います。文字列自体を過ぎたある時点でnullターミネータを見つけることになります。これは、nullで終了しておらず、最終的に29バイトになるためです。

read2正直なところ、なぜ同じことをしているのかわかりません。上記の理由については間違っている可能性がread1あり、29バイト(c文字列の4文字/バイトを差し引いたもの)が、アーキテクチャおよびコンパイラによるSTLの実装における文字列の最小運用コストです。

いずれにせよ、さまざまな可能性を絞り込むために、文字列をnullで終了し、read01read1つの追加要素を割り当てて最後の要素を設定する'\0'か、追加の2番目のパラメーターを受け取る代替文字列コンストラクターを使用して実験を再試行することをお勧めしますこれは、コピーする文字数を示します。

string(non_null_terminated_string, this_many_characters_to_copy)
于 2013-03-15T01:42:13.470 に答える
1

read0 では、空の cstr (長さゼロ) から str を初期化しています。read1 と read2 では、空でない文字列から str を初期化しています。後者の場合に実際に割り当てられるヒープの量 (29 バイト) は、ヒープ管理をより高速かつ簡単にするために必要な量よりも大きくなります。

また、read1 にバグがあります: cstr に "----" を含めたい場合は、cstr[4] ではなく cstr[5] が必要です。配列には、文字列を終了するゼロのためのスペースが必要です。そして、おそらく memset(cstr, '-', 4) ではなく strcpy(cstr, "----") を使用する必要があります。そうしないと、cstr に (必要な) ゼロ ターミネータがありません。

于 2013-03-15T01:54:32.600 に答える