14

STL 標準では、 from std::string を参照カウントする必要はありません。しかし実際には、ほとんどの C++ 実装は参照カウントされたコピー オン ライト文字列を提供し、文字列をプリミティブ型として値で渡すことができます。また、これらの実装 (少なくとも g++) は、アトミック操作を使用して、これらの文字列をロックフリーにし、スレッドセーフにします。

簡単なテストは、コピーオンライトのセマンティクスを示しています。

#include <iostream>
#include <string>

using namespace std;

void foo(string s)
{
    cout<<(void*)s.c_str()<<endl;
    string ss=s;
    cout<<(void*)ss.c_str()<<endl;
    char p=ss[0];
    cout<<(void*)ss.c_str()<<endl;
}

int main()
{
    string s="coocko";
    cout<<(void*)s.c_str()<<endl;
    foo(s);
    cout<<(void*)s.c_str()<<endl;
}

非定数メンバーが使用された後、2 つのアドレスのみが正確に出力されます。

HP、GCC、Intel コンパイラを使用してこのコードをテストしたところ、同様の結果が得られました。文字列はコピー オン ライト コンテナーとして機能します。

一方、VC++ 2005 では、各文字列が完全にコピーされていることが明確に示されています。

なんで?

私は、VC++6.0 にスレッドセーフではない参照カウントの実装があり、ランダムなプログラム クラッシュを引き起こすバグがあったことを知っています。これが理由ですか?彼らは、それが一般的な慣行であっても、もはや参照カウントを使用することを恐れているだけですか? 問題を修正することよりも、参照カウントをまったく使用しないことを好むのですか?

ありがとう

4

5 に答える 5

22

refcounting/copy-on-write はマルチスレッド コードの逆最適化であることが多いため、ますます多くのstd::string実装が refcounting/copy-on-write から離れると思います。

Herb Sutter の記事Optimizations That Are Not (In a Multithreaded World)を参照してください。

于 2009-04-01T19:40:38.187 に答える
11

STLの実際には、参照カウントを使用する場合、セマンティクスが非参照カウントバージョンの場合と同じである必要があります。これは一般的なケースでは簡単ではありません(そのため、文字列クラスに記述しないでください)。

次の状況のた​​め:

std::string   x("This is a string");
char&         x5 = x[5];
std::string   y(x);

x5 = '*';

詳細については、 http: //www.sgi.com/tech/stl/string_discussion.htmlを参照してください。

于 2009-04-01T19:59:00.637 に答える
7

Martin と Michael が述べているように、コピー オン ライト (COW) は、価値があるよりも多くの問題を抱えていることがよくあります。詳細については、Mad COW 病に関するKelvin Heneyによるこの優れた記事を参照してください。小さな文字列の最適化のパフォーマンスが優れていると述べたのはAndrei Alexandrescuであると思います。多くのアプリケーションで(しかし、記事が見つかりません)。

小さな文字列の最適化では、文字列オブジェクトを大きくし、小さな文字列のヒープ割り当てを回避します。おもちゃの実装は次のようになります。

class string {
    char *begin_, *end_, *capacity_;
    char buff_[64]; // pick optimal size (or template argument)
public:
    string(const char* str)
    {
        size_t len = strlen(str);
        if (len < sizeof(buff_))
        {
            strcpy(buff_, str);
            begin_ = buff_;
            capacity_ = buff_ + sizeof(buff_);
        }
        else
        {
            begin_ = strdup(str);
            capacity_ = begin_ + len;
        }
        end_ = begin_+len;
    }

    ~string()
    {
        if (begin_ != buff_)
            free(begin_); // strdup requires free 
    }
    // ...
};
于 2009-04-02T19:01:11.713 に答える
5

おそらくMicrosoftは、文字列のコピーは大きな問題ではないと判断しました。ほとんどすべてのC ++コードは、可能な限り参照渡しを使用しているからです。参照カウントを維持することは、おそらく彼らが支払う価値がないと判断した(ロックを無視して)スペースと時間のオーバーヘッドがあります。

またはそうでないかもしれません。これが懸念される場合は、アプリケーションのプロファイルを作成して、文字列のコピーが主要なオーバーヘッドであるかどうか、および別の文字列実装に切り替えるかどうかを判断する必要があります。

于 2009-04-01T19:43:40.877 に答える
1

これは主な理由ではありませんが、win32プラットフォームでのような動作をする多くの誤ったコードを見ましたconst_cast< char* >( str.c_str() )

たぶん、Microsoftはこれを知っていて、開発者の面倒を見てくれます:)

于 2009-04-01T19:46:18.330 に答える