2

コールバックを処理する非常に単純なクラスがあります。発信者がマネージャからのコールバックを要求します。Callback オブジェクトが呼び出し元によって保持されている限り、それは有効なままです。ただし、オブジェクトが終了すると、そのデストラクタが Manager 内のポインタを NULL に設定するため、次に遭遇したときにオブジェクトを破棄することが認識されます。

...または少なくとも、それが私が求めている基本的な考え方です。

class Manager{
public:
    void executeOnList() { ... }

    Callback requestCallback(Drawable * target){
          Drawable ** ptr = list.add(target);
          return Callback(ptr);  // <-- the point of interest
    }
private:
    List list;
};


class Callback{
    friend Manager;
private:
    Callback(Drawable ** targetPtr){
        drawablePtr = targetPtr;
    }
public:
    ~Callback(){
        (*drawablePtr) = NULL;  // <-- dtor of interest
    }
private:
    Drawable ** drawablePtr;
};

私の質問は、構造体を呼び出し元に返す前にManager::requestCallback()デストラクタを呼び出すでしょうか?Callback

その場合、(多かれ少なかれ)Callbackの機能の背後にある基本的な考え方を維持しながら、これを防ぐ方法はありますか?

4

3 に答える 3

3

スタック上にあるすべてのオブジェクトは、スコープ外になると自動的に破棄されます。つまり、概念的には、一時オブジェクトは関数から返されたときにスコープ外になります。とはいえ、オブジェクトをコピーして返すときに、コンパイラによって省略される可能性があります。その場合、return ステートメントの一時オブジェクトはまったく存在しないようです。ただし、コピー省略が発生するかどうかは最適化であり、保証されていません。

あなたの場合、デストラクタだけに依存してもうまくいかないようです。ただし、機能する可能性があるのは、渡される一時オブジェクトと保持されている (名前が付けられているか、指されている) オブジェクトを区別することです。基本的な考え方は、ポインタへのポインターをオブジェクトが所有するリソースと見なし、実際の所有者が破棄されたstd::unique_ptr<T>場合 ( と同様)、またはすべての所有者が破棄された場合( と同様) にのみリセットすることstd::shared_ptr<T>です。右辺値参照を使用できると仮定すると、両方の形式を正しく取得できます。それ以外の場合は、共有所有権しか取得できません。

以下は、単一所有権のロジックがどのように見えるかの簡単な概要です。

class Callback{
    friend Manager;
private:
    Callback(Drawable ** targetPtr){
        drawablePtr = targetPtr;
    }
public:
    Callback(Callback&& other):
        drawablePtr(other.drawablePtr) {
        other.drawablePtr = 0;
    }
    ~Callback(){
        if (drawablePtr) {
            (*drawablePtr) = 0;
        }
    }
private:
    Drawable ** drawablePtr;
};

右辺値セマンティクスを使用できない場合でも、実際には同じロジックを使用できますが、コピーが作成されたときに名前付きオブジェクトから「リソース」が誤って盗まれるリスクがあります。ムーブ コンストラクターを使用すると、このリスクを回避できます。

于 2013-08-18T11:29:29.567 に答える
2

移動コンストラクタ (c++11) またはコピー デストラクタを追加できます。

class Callback{
    friend Manager;
private:
    explicit Callback(Drawable** targetPtr) : drawablePtr(targetPtr) {}
    // C++11
    Callback(Callback&& rhs) : drawablePtr(rhs.drawablePtr) { rhs.drawablePtr = NULL; }
    // else
    Callback(Callback& rhs) : drawablePtr(rhs.drawablePtr) { rhs.drawablePtr = NULL; }
public:
    ~Callback(){
        if (drawablePtr) { (*drawablePtr) = NULL; }
    }
private:
    Drawable ** drawablePtr;
};
于 2013-08-18T11:27:53.853 に答える