7

QList、、QQueueのようQHashなすべてのデータオブジェクトに存在するように見えるメソッドについてつまずいた

これまでに調べたところ、ソースコードを見ることができます。

inline void setSharable(bool sharable) {
    if (!sharable) detach(); d->sharable = sharable;
}

qlist.h 内( 117 行目)。

QListしかし、それは、QQueueQHash...にどのような影響を与えるのでしょうか? そして、それは何らかの形でスレッド化に関連していますか (これは合理的に聞こえます)?

回答ありがとうございます。実際の知識がある場合にのみ回答してください。

4

2 に答える 2

6

誰もこれ以上明確に言うことはできません。

http://qt.nokia.com/doc/4.6/implicit-sharing.html

この方法でコンテナを実現するのが一般的な方法です。

于 2010-03-27T20:45:12.817 に答える
5

あなたが求めている共有可能な状態は、マルチスレッドとは何の関係もありません。代わりに、内部状態への参照を渡すコピー オン ライト データ クラス (シングル スレッドのものも含む) の実装の詳細です。

CoW を使用して実装されたクラスStringを考えてみましょう (説明のために、このクラスはスレッド化されたコンテキストでは使用できません。アクセスd->refcountが同期されていないためです。また、内部char配列が で終了することも保証'\0'されず、あなたの祖母;あなたは警告されました):

struct StringRep {
    StringRep()
        : capacity(0), size(0), refcount(0), sharable(true), data(0) {}
    ~StringRep() { delete[] data; }
    size_t capacity, size, refcount;
    bool sharable; // later...
    char * data;
};

class String {
    StringRep * d;
public:
    String() : d(new StringRep) { ++d->refcount; }
    ~String() { if (--d->refcount <= 0) delete d; }
    explicit String(const char * s)
        : d(new StringRep)
    {
        ++d->refcount;
        d->size = d->capacity = strlen(s);
        d->data = new char[d->size];
        memcpy(d->data, s, d->size);
    }
    String(const String &other)
        : d(other.d)
    {
        ++d->refcount;
    }
    void swap(String &other) { std::swap(d, other.d); }
    String &operator=(const String &other) {
        String(other).swap(*this); // copy-swap trick
        return *this;
    }

そして、mutating メソッドと const メソッドのそれぞれのサンプル関数:

    void detach() {
        if (d->refcount == 1)
            return;
        StringRep * newRep = new StringRep(*d);
        ++newRep->refcount;
        newRep->data = new char[d->size];
        memcpy(newRep->data, d->data, d->size);
        --d->refcount;
        d = newRep;
    }

    void resize(size_t newSize) {
        if (newSize == d->size)
            return;
        detach(); // mutator methods need to detach
        if (newSize < d->size) {
            d->size = newSize;
        } else if (newSize > d->size) {
           char * newData = new char[newSize];
           memcpy(newData, d->data, d->size);
           delete[] d->data;
           d->data = newData;
        }
    }

    char operator[](size_t idx) const {
        // no detach() here, we're in a const method
        return d->data[idx];
    }

};

ここまでは順調ですね。しかし、 mutable を提供したい場合はどうすればよいoperator[]でしょうか?

    char & operator[](size_t idx) {
        detach(); // make sure we're not changing all the copies
                  // in case the returned reference is written to
        return d->data[idx];
    }

この単純な実装には欠陥があります。次のシナリオを検討してください。

    String s1("Hello World!");
    char & W = s1[7]; // hold reference to the W
    assert( W == 'W' );
    const String s1(s2); // Shallow copy, but s1, s2 should now
                         // act independently
    W = 'w'; // modify s1 _only_ (or so we think)
    assert( W == 'w' ); // ok
    assert( s1[7] == 'w' ); // ok
    assert( s2[7] == 'W' ); // boom! s2[7] == 'w' instead!

これを防ぐにStringは、内部データへの参照を渡すときに共有不可とマークする必要があります。これにより、内部データから取得されるコピーは常に深いものになります。したがって、次detach()char & operator[]ように調整する必要があります。

    void detach() {
        if (d->refcount == 1 && /*new*/ d->sharable)
            return;
        // rest as above
    }
    char & operator[](size_t idx) {
        detach();
        d->shareable = false; // new
        return d->data[idx];
    }

shareableいつ状態をリセットするのtrueですか? 一般的な手法は、const 以外のメソッドを呼び出すときに内部状態への参照が無効になると言うものです。そのため、shareableは にリセットされtrueます。すべての非 const 関数はdetach()を呼び出すため、そこでリセットできるshareableため、detach()最終的には次のようになります。

    void detach() {
        if (d->refcount == 1 && d->sharable) {
            d->sharable = true; // new
            return;
        }
        d->sharable = true; // new
        StringRep * newRep = new StringRep(*d);
        ++newRep->refcount;
        newRep->data = new char[d->size+1];
        memcpy(newRep->data, d->data, d->size+1);
        --d->refcount;
        d = newRep;
    }
于 2012-06-19T20:08:39.533 に答える