4

解決方法がわからない問題が発生しました..

汎用オブジェクト プールがあります。オブジェクトが要求されると、プールはQSharedPointer、カスタム Deleter が指定された状態で、最初に使用可能なインスタンスに戻ります。QSharedPointerインスタンスの参照カウントが 0の場合、デリータはオブジェクトをプールに返すだけです。プレーンなオブジェクトの場合はすべて正常に機能します。QObjectQt 5 でコンパイルすると、後継者に対しても正常に動作します。

ただし、Qt 4.6 でコンパイルすると、問題が発生します。同じオブジェクトが 2 回目に要求されると、アプリケーションはエラーで終了します。

「QSharedPointer: ポインター xxx には既に参照カウントがあります」

簡単なテストを書きました:

QObject* obj = new QObject();
QSharedPointer<QObject> p(obj, deleter); // deleter here does nothing
p.clear();
QSharedPointer<QObject> p2(obj, deleter); // this crashes the app

Qt 4.6でコンパイルすると、これは確かに失敗します。繰り返しますが、QT 5.x では正常に動作します。

Qt ソース コードを調べるとQObject、これがパラメーターQObjectとして使用されると、 4.6 が内部参照カウンターを初期化することが明らかになりました。QSharedPointerこれは、2 つのスマート ポインターが同じオブジェクトを指すことがないようにし、デストラクタでのみリセットされるようにするために行われます。

QObjectインスタンスがスマート ポインターにラップされている場合、Qt5 は参照カウンターの値をチェックしないため、機能します。

古い Qt バージョンの回避策を知っている人はいますか? refカウンターを含む内部Qtステータスを完全にリセットする方法はありますか? どんなヒントでも大歓迎です。

4

2 に答える 2

0

メモリの割り当てと割り当て解除を回避するためにプールがあると仮定すると、メモリを一度だけ割り当ててから、「新しい」オブジェクトを要求して返すときにコンストラクタとデストラクタを明示的に呼び出す必要があります。

/* deleter calls destructor explicitly when return object to pool */
void deleter(QObject *object) {
    object->~QObject();
    mark_as_available();
}

/* allocate (one object) pool memory without calling constructor*/
QObject *object = ::operator new(sizeof(QObject));

/* request object - calling constructor on already allocated memory */
mark_as_taken();
return QSharedPointer(::new (object) QObject, &deleter);

/* deallocate pool memory without calling destructor */
::operator delete(object);
于 2014-08-11T18:08:15.657 に答える