5

そのような場合:

    class A
    {
        //implementation
    };

    class B
    {
     public:
         B();
        ~B();
     private:
         std::vector<std::shared_ptr<A>> _innerArray;
    };

B()有効な状態のオブジェクトを作成するには、で何をすればよいですか?A配列内のすべてのオブジェクトに対してデフォルトのコンストラクターを手動で呼び出す必要がありますか?そして、私は何か特別なことをする必要があります~B()か?Bクラスが悪いデザインの例である場合、それをより良くする方法を自由に言ってください。ありがとう。

編集 だから、これが私がここで本当に必要としているもののスキームです。

ここに画像の説明を入力してください

したがって、Aの配列と他のすべてのオブジェクトにのみ格納される実際の値は、接続を格納するためのものです。最も簡単な例-A=ドット、B =選択したドットを通る線(または曲線)、C=線で表される平面。それが質問をより正確にすることを願っています。

4

5 に答える 5

5

有効な状態でオブジェクトを作成するために、Bこれ以上何もする必要はありません。のコンストラクタとデストラクタを宣言して実装する必要もありませんBstd::vector<std::shared_ptr<A>>のメンバーは、のコンストラクターでBデフォルトで初期化されますB。つまり、コンテナーにはまだ要素がありません。また、デストラクタの~Bおかげで適切に削除されます。std::vectorstd::shared_ptr

一方、たとえば何らかの方法で初期化する場合(つまり、3つの値) 、コンストラクター初期化リストでコンストラクターをstd::vector使用できます。例えば:std::initializer_listB

class B
{
 public:
     B(): _innerArray{ std::make_shared<A>(),
                       std::make_shared<A>(),
                       std::make_shared<A>() } {}
    ~B() {}
 private:
     std::vector<std::shared_ptr<A>> _innerArray;
};

std::make_sharedこれは完全な転送を使用するためA、クラスオブジェクト自体ではなく、関数の引数としてのコンストラクター引数を渡すことに注意してください。

デザインに関する懸念に答えるには、メンバーを共有する前に、まずベクター内のメンバーの独占的所有権について考えることをお勧めします。

class B
{
 public:
     B();
    ~B();
 private:
     std::vector<std::unique_ptr<A>> _innerArray;
};

上記の実装は、多くの理由でより効果的です。まず第一に、それはあなたのデザインを誰がAsの寿命に責任があるかについてより明確にします。Nextstd::unique_ptrは、スレッドセーフな参照カウントを必要としないため、より高速です。最後になりましたが、追加のメモリ(通常のCポインタと比較して)は必要ありませんが、std::shared_ptr共有状態データを格納するのに数十バイト(24〜48)かかる場合があり、小さなクラスで操作する場合は非常に効果がありません。そのため、私は常にstd::unique_ptr最初の手段としてスマートポインターを使用し、std::shared_ptr本当に必要な場合にのみフォールバックします。

編集:

あなたの編集に答えて、私はクラスの3つのコンテナを作成しAますB、、C。事実に応じて、それらをポリモーフィックにする必要があるかどうかに応じて、そのような値(非ポリモーフィックタイプ)を格納します。

std::deque<A> as;
std::deque<B> bs;
std::deque<C> cs;

または(ポリモーフィックタイプ):

std::vector<std::unique_ptr<A>> as;
std::vector<std::unique_ptr<B>> bs;
std::vector<std::unique_ptr<C>> cs;

その順序で(asより長く生きる必要があり、より長くbs生きるbs必要がありcsます)。そうすれば、スマートポインターを使用せずに、insideクラスとinsideクラスを作成std::vector<A*>できBますstd::vector<B*>C

それがお役に立てば幸いです。

編集:

コンテナ要素への参照/ポインタが。を使用したコンテナ拡張に耐えられるようにする最初のケースでに変更std::vectorされました。ただし、要素の消去、並べ替え、その他のものには耐えられません。std::dequepush_back()

于 2012-11-07T11:41:21.637 に答える
2

このようにすると、ベクトルのサイズはゼロ要素になります。つまり、内容は簡単に適切に初期化されます。ベクトルが正のサイズである場合(たとえばresize、ベクトルを呼び出した後)、各要素は適切に初期化されます。要素はshared_ptrsであるため、のデフォルトコンストラクターshared_ptrが呼び出されます。これは、空のポインターのベクトルになってしまうことを意味します。

別のコンテナーからコンテンツをコピーする場合は、イテレーターバージョンのベクターコンストラクターを使用します。

B (SomeContainerTypeContainingSharedPointers container)
: _innerArray (container.begin (), container.end () ) {
}

コンテナからではなく、他の場所からベクトルを初期化する場合(たとえば、オブジェクトをその場で作成する場合)、入力イテレータタイプを自分で記述します(つまり、一種の「ファクトリイテレータ」)。

于 2012-11-07T11:21:09.823 に答える
1

ベクトルは空なので、デフォルトのコンストラクターで特別なことをする必要はありません。また、どちらでも何もする必要はありませんB()。ベクトルのデストラクタが呼び出されると、の参照カウントはshared_ptrs自動的に減少します。

于 2012-11-07T11:22:07.370 に答える
1

Btのデフォルトでstd::shared_ptr<A>は、内部ptrに。が入力されNULLます。スマートポインタを作成するには、次を使用しますstd::make_shared

_innerArray.push_back(std::make_shared<A>(/*constructor params here*/));

しかし、あなたの例では、ベクトルは空です。

于 2012-11-07T11:22:18.230 に答える
0

デフォルトのコンストラクターは、必要なすべてをすでに実行しています。あなたB()も損失なしで除外することができます。

于 2012-11-07T11:23:38.883 に答える