2

C++で設計のジレンマを達成するための最良の方法は何でしょうか...

別のクラスのタイプのメンバー変数を含むクラスがあり、作成される実際のオブジェクトはの時点でBase作成されます。DerivedBase

クラスはこれらの変数を変更する必要はなく、それらを使用するだけです。他の誰かがこれらの変数を作成しています。これらのDerivedクラスは、私のクラスのコンテナ(std :: vector、QListなど)クラスにも移動する必要があるため、適切なコピーの構築と割り当てを実行する必要があります。

だから、私は何が最高かもしれないと思っていました:

  1. メンバー変数をとして作成し、Base*それらとそれらが使用するメモリを管理しましょう。これは、古典的なメモリリークの問題につながります...誰かがオブジェクトを使用しなくなったときに、オブジェクトを削除するのを忘れるだけです。
  2. メンバー変数をとして作成し、Base&どこかでスコープから外れたときに消えないように祈りましょう。
4

5 に答える 5

1

@hansmaadはちょうどいいです。オブジェクトの存続期間の制御に問題がある場合は、オブジェクトを作成または管理する人と所有権を共有する必要があります。
2つのオプションがあります:
1)boost::shared_ptrまたは変更せずstd::tr1::shared_ptr
にこのクラスを任意のタイプに簡単に使用できますが、マルチスレッド環境で作業している場合、スレッドセーフを実現するのは非常に困難であり、共有としてオブジェクトを作成するかどうかを忘れないでくださいこのクラスの1つを使用すると、オブジェクトの存続期間を直接管理するべきではなく、rawポインターから新しい共有オブジェクトを作成することは違法であり、常にコンストラクト共有オブジェクトをコピーする必要があります。例えば:BaseBaseshared_ptr

boost::shared_ptr<Base> sharedObject( new Drived() );
boost::shared_ptr<Base> validCopy( sharedObject );    // Ok share ownership
Base* p = sharedObject.get();
boost::shared_ptr<Base> invalidCopy( p );    // Error, can't create new shared_ptr from raw pointer

2)boost::intrusive_ptr
参照カウントがクラスに実装されているため、rawポインターから構築できるため、スレッドセーフにすることが簡単にでき、rawポインターまたはスマートポインターとして渡すことができますが、クラスの定義を変更して参照カウントを追加する必要があります機構

于 2012-08-29T09:45:14.747 に答える
1

コンパイラーが生成した代入とムーブ代入は間違ったことをするか、期待どおりではないため、参照メンバー変数を使用することは常に不適切な選択です。

メンバー変数のポインターまたはスマートポインターに固執します。

于 2012-08-29T09:27:58.023 に答える
0

参照メンバー変数で最初に考慮すべきことは、クラス(ではなくDerived、ポインターまたは参照であるデータメンバーを持つクラスBase)が値のセマンティクスを必要とするかどうかです(これは、「適切にコピーして割り当てる」という別の言い方です。 ")。

もしそうなら、参照メンバー変数は、再装着できないため、多かれ少なかれすぐに問題から外れます。とにかくそれらを使用できるいくつかの奇妙な状況がありますが、使用しないと想定して、ポインターを使用することもできます。

参照データメンバーは、「エンティティセマンティクス」を持つタイプ(つまり、まったく割り当てられず、コピーされる場合とされない場合があります)に役立つ場合がありますが、それでも大きなメリットはありません。const Base&また、パラメーターを受け取るコンストラクターを作成し、それを参照データメンバー[*]に格納するというエラーにあなたを誘惑する可能性もあります。

オブジェクトの所有者(およびオブジェクトの解放の責任者)は、ポインターと参照のどちらを使用するかとは完全に無関係です。おそらく、所有するものに参照を使用しないという一般的な規則があります(また、所有するものにrawポインターを使用しないという規則があるはずです。適切なスマート・ポインターを選択または作成する必要があります。スマート・ポインター・クラスはrawポインターを保持できます)。しかし、それは単なる慣習です。ポインタがある場合にのみ、メモリを管理していると思い込まないでください。

概要:ポインタを使用してから、メモリの管理方法を個別に決定します。

[*]これは間違いです。最終的に誰かが初期化子で一時オブジェクトを誤って使用し、その参照データメンバーを持つクラスのインスタンスが一時オブジェクトよりも長持ちするためです。このため、const &オブジェクトを変更しなくても、戻った後に使用するために参照を格納するものは、パラメーターを受け取らないようにする必要があります。彼らはconst *代わりに取ることができます。C ++ 11では、一時的なオーバーロードが選択されるのを防ぐために、右辺値参照オーバーロードもあれば問題ないと思いますが、const&まだ試したことはありません。

于 2012-08-29T09:35:31.540 に答える
0

次の理由から、ベクトル (つまり、 vector<Base *>、not ) とコンテナー クラスの両方にポインターを使用します。vector<Base>

  • Derived オブジェクトをベクトルに格納すると、そのベクトルのサイズが変更され、すべてのオブジェクトがメモリ内の新しい場所に「移動」する可能性があります。これにより、すべての未解決のポインターと参照が無効になります
  • コンテナーに参照が含まれている場合、参照は定義されている場合にのみバインドできるため、ポインターが含まれている場合ほど簡単にコピーすることはできません (したがって、MyClass::MyClass(int &a) : memberA(a) {}メモリが機能する場合は を介し​​たコンストラクターで)
  • ポインターは、必要に応じて set メソッドなどの他の手段で変更でき、情報がない場合は null に設定できます。

所有権に関する限り、jrok が最初に言ったのshared_ptr<>は、あなたの友達です。車輪を再発明するのではなく、標準ライブラリを利用して単純化してください。その場合に心配する必要があるのは、循環ポインターだけです (つまり、オブジェクトはそれ自体を指しているため、常に有効なポインターが存在します)。

于 2012-08-29T09:31:05.150 に答える
0

所有権について考える必要があります。そのオブジェクトの所有者は誰ですか? この質問に対する明確な答えがない場合は、std::shared_ptr<Base>(共有所有権) を使用する必要があります。そのオブジェクトを所有する 1 つのクラスがあり、他のすべてのクラスがそれらを使用するだけの場合はstd::unique_ptr<Base>、のようなポインタ コンテナを使用できますboost::ptr_vector。または、具体的なインスタンスだけを所有するクラスにポリモーフィズムがない場合。他のすべてのクラスでは、そのオブジェクトへのプレーン ポインター (クラス メンバーとして推奨) または参照 (null が許可されていない場合は引数として推奨) を使用できます。

ケース 1 - 共有所有権

class IWorkOnBaseObjects
{
    std::vector<std::shared_ptr<Base>> mySubset;
};

class MeToo
{
    std::shared_ptr<Base> iNeedThisOne;
};

ケース 2

class HomeOfBaseObjects
{
    std::vector<std::uniqe_ptr<Base>> baseObjects;
};

class IWorkOnBaseObjects
{
    std::vector<Base*> mySubset;
};

ケース 3

class A : public Base{};
class B : public Base{};

class HomeOfAObjects
{
    std::vector<A> aObjects;
};

class HomeOfBObjects
{
    std::vector<B> bObjects;
};

class INeedABaseObject
{
    Base* thisOne;
};
于 2012-08-29T09:25:36.363 に答える