1

私は C++ フレームワークに取り組んでおり、多数のコア クラスに自動メモリ管理を適用したいと考えています。これまでのところ、私は標準的なアプローチを持っています

class Foo 
{

public:

  static
  shared_ptr<Foo> init() 
  {
    return shared_ptr<Foo>(new Foo);
  }

  ~Foo() 
  {
  }

protected:

  Foo()
  {
  }

};


// Example of use
shared_ptr<Foo> f = Foo::init();

ただし、 Foo をサブクラス化すると、上記は壊れます。init()継承shared_ptr<Foo>されているため、のインスタンスへのポインターを含むものが返されますFoo

これに対するエレガントな解決策を考えられる人はいますか? おそらく、クラスのインスタンスを(半)手動でラップすることに固執する必要がありshared_ptrますか?これにより、新しい名前付きコンストラクターを宣言せずに、パラメーター化されたコンストラクターを公開することもできます...

すなわち。

template <typename T>
shared_ptr<T> make_shared(T* ptr)
{
  return shared_ptr<T>(ptr)
}

// Example
shared_ptr<T> 
  f1 = make_shared(new Foo()),
  f2 = make_shared(new Foo(1,2));
4

8 に答える 8

4

私はこのようなことを試みます:

template<class T>
class creator
{
  public:
    static shared_ptr<T> init()
    {
      return(shared_ptr<T>(new T));
    }
};

class A : public creator<A>
{
};

class B : public A, public creator<B>
{
  public:
    using make_shared<B>::init;
};

// example use
shared_ptr<A> a = A::init();
shared_ptr<B> b = B::init();

しかし、これはあなたが提案したスタンドアロンのテンプレートと比較して必ずしもあなたに物事を節約するわけではありません。

編集:私は前の答えを逃しました、これは同じ考えのようです。

于 2009-02-12T09:11:10.917 に答える
2

これが何を達成するのかわかりません。単純にshared_ptrを宣言する以外に、このinit関数を使用して追加のメモリ管理を行っているようには見えません。

int main( void )
{
    shared_ptr<foo> a = foo::init();
    shared_ptr<foo> b( new foo );
}

違いは何ですか。shared_ptr はメモリ管理を提供しますが、init には何もありません。

于 2009-02-12T09:36:11.823 に答える
2

It seems that the goal is to make it impossible for users of the classes to call the constructors directly, and only expose a routine which returns shared_ptr's.

But if you want to apply this pattern, you need to replicate it in all the subclasses. The subclasses cannot automatically "inherit" init() so that init() would still call the subclass constructor, because init() is not a virtual method and is called without an object.

I would leave the constructors exposed as usual and just use the standard

shared_ptr<X> x = new X();

This keeps cognitive burden low, is readable, and remains flexible. This is how we program in our company with reference counted objects, anyway.

于 2009-02-12T18:07:22.220 に答える
1

どうですか...

template<typename Derived>
class Foo 
{
public:

    static shared_ptr<Derived> init() 
    {
        return shared_ptr<Derived>(new Derived);
    }

    ~Foo() 
    {
    }

protected:

    Foo()
    {
    }

};


class Bar : public Foo<Bar>
{
};

int _tmain(int argc, _TCHAR* argv[])
{
    shared_ptr<Bar> b = Foo<Bar>::init(); 
    return 0;
}
于 2009-02-12T08:54:09.070 に答える
1

仮想デストラクタで共通のベースを導入し、そこから必要なすべてのクラスを継承し、単純に new を使用してみませんか?

于 2009-02-12T09:35:24.710 に答える
1

一般に、コンストラクターを非表示にしてオブジェクトの作成を強制することはお勧めできませんshared_ptr。私はここで、まさにそれを行った社内の lib を使用した個人的な経験から話しています。割り当てられたオブジェクトを常にラップするようにしたい場合は、これらの型のインスタンスを格納するすべての引数とメンバーが、ネイキッド ポインターまたは参照の代わりにshared_ptrorを期待していることを確認してください。weak_ptrまた、これらのクラスを から派生させることもできenable_shared_from_thisます。すべてのオブジェクトが共有されているシステムでは、ある時点でthis、これらの他のオブジェクトのメソッドの 1 つにポインタを渡す必要があり、それらは のみを受け入れるように設計されているためshared_ptr、オブジェクトがinternal_weak_this破壊されないようにするためにno を持っている場合、あなたはかなり悪い状態です。

于 2009-02-12T20:27:18.153 に答える
0

ちなみに、大規模なC ++フレームワークでは、「自動メモリ管理」をコーダーから隠すのが一般的です。これにより、彼はより短く単純なコードを書くことができます。たとえば、Qtでは次のことができます。

QPixmap foo() {
    QPixmap pixmap(10, 10);
    return pixmap;
}

void bar() {
    QPixmap a = foo(); // no copying occurs, internal refcount incremented.
    QPixmap b = a;     // ditto.
    QPainter p(&b);
    p.drawPoint(5, 5); // data can no longer be shared, so a copy is made.
    // at this point 'a' is still unchanged!
    p.end();
}

Qtの多くのものと同様に、これはJavaオブジェクトモデルを模倣しますが、コピーオンライト暗黙の共有と呼ばれます)を実装することでさらに進んでいます。これは、を呼び出す必要がないC++コーダーにとってAPIの動作をそれほど驚くことのないものにすることを目的としていますclone()

これは、1つの石で2羽の鳥を殺すd-pointerイディオムを介して実装されます。自動メモリ管理を提供し、実装をユーザーから隔離ます(pimpl)。

QPixmapの実際の実装は、qpixmap.cppqpixmap.hで確認できます。

于 2009-12-29T11:15:45.210 に答える
0

階層全体のすべてのタイプで静的ファクトリ関数が必要です。

class Foo
{
public:
    static shared_ptr< Foo > instantiate( /* potential arguments */ )
    {
           return shared_ptr< Foo >( new Foo( /* potential arguments */ );
    }

// blah blah blah
};

class Bar : public Foo
{
public:
    static shared_ptr< Bar > instantiate( /* potential arguments */ )
    {
           return shared_ptr< Bar >( new Bar( /* potential arguments */ );
    }

// blah blah blah
};

それでも混乱する場合は、sourceforge で CppCodeProvider を検索して、そこでどのように処理されているかを確認してください。

于 2009-02-12T17:56:18.423 に答える