1

item28 in More Effective C++を読んでいるときに質問に遭遇しました。この項目では、作成者は、メンバー テンプレートをに変換できるSmartPtrように使用できることを示しています。 次のコードは本と同じではありませんが、同じ効果があります。 SmartPtr<Cassette>SmartPtr<MusicProduct>

#include <iostream>

class Base {};
class Derived : public Base {};

template<typename T>
class smart {
public:
    smart(T* ptr)
        : ptr(ptr)
    {}

    template<typename U>
    operator smart<U>()
    {
        return smart<U>(ptr);
    }

    ~smart()
    {
        delete ptr;
    }
private:
    T* ptr;
};

void test(const smart<Base>& ) {}

int main()
{
    smart<Derived> sd(new Derived);
    test(sd);
    return 0;
}

実際、コンパイルエラーなしでコンパイルできます。しかし、実行可能ファイルを実行すると、コア ダンプが発生しました。sdこれは、変換演算子のメンバー関数が、同じ ptr へのポインター(その型は)を持つ一時的なスマートを作成するためだと思いますsmart<Derived>。したがって、delete ディレクティブは 2 回動作します。さらに、test を呼び出した後は、 inが既に削除されているsdため、これ以上使用することはできません。 今私の質問は次のとおりです。 ptrsd

  • 私の考えは正しいですか?または、私のコードは本の元のコードと同じではありませんか?
  • 私の考えが正しければ、これを行う方法はありますか?

どうもありがとうございました。

4

2 に答える 2

0

はい、コードの問題をかなり正確に説明しました。

動作させる方法に関しては、浅いコピーで問題が発生した場合とほぼ同じように、代わりに深いコピーを実行してください。つまり、同じデータへの別のポインターを作成するだけでなく、データを複製し、2 番目のオブジェクトが元のデータではなくデータの複製を指すようにする必要があります。

または、参照カウント ポインターを使用し、コピーを実行するときに参照カウントをインクリメントし、コピーが破棄されるときにそれをデクリメントします。カウントが 0 になったら (それ以前ではなく)、指示先データを削除します。

一般的に言えば、これらすべてを行うことは避けてください。比較的最新のコンパイラを使用していると仮定すると、標準ライブラリには、多くのスマート ポインターのニーズを処理できるashared_ptrと aが既に含まれているはずです。unique_ptr

于 2013-11-05T03:56:18.293 に答える
0

あなたの解釈は正しいです。変換演算子は、同じ基になるオブジェクトへのポインターを保持する別のオブジェクトを作成します。スコープの外に出ると破棄され、次に が呼び出されますdelete

最後の質問がよくわかりません。これが役立つかどうかという質問であれば、正しく実装すれば役立つ可能性があります。たとえば、生のポインターの代わりに、使用していたメモリを手動で割り当て/削除する場合、問題なく動作しますstd::shared_ptr。他の場合では、動的に割り当てられたオブジェクトさえないかもしれません...これは単なるツールです。意味のある場所で使用してください。

于 2013-11-05T03:57:13.127 に答える