学習C++:帰国の参照および周辺のスライス
-
25-09-2019 - |
質問
ん悪魔の時に理解しました。以下のコードを考えてみます::
class Animal
{
public:
virtual void makeSound() {cout << "rawr" << endl;}
};
class Dog : public Animal
{
public:
virtual void makeSound() {cout << "bark" << endl;}
};
Animal* pFunc()
{
return new Dog();
}
Animal& rFunc()
{
return *(new Dog());
}
Animal vFunc()
{
return Dog();
}
int main()
{
Animal* p = pFunc();
p->makeSound();
Animal& r1 = rFunc();
r1.makeSound();
Animal r2 = rFunc();
r2.makeSound();
Animal v = vFunc();
v.makeSound();
}
その結果:"皮皮rawr rawr".
Javaによる考え方になっているようで壊れた私の概念のC++の結果るというのは、皮皮皮皮".理解していらっ 前の質問 この違いによるスライスして理解しようスライスです。
がついている機能を返します動物の価値はないのです。
- いかに正しく最も近接することができま読み取れなくなってきた 参考?
- また、当然の責務の一つのrFuncインターフェースの参照が返され割り当て動物&?(又はその他の意図的に割り当てを参照し、動物、スライスを破棄しての多型.)
- どのように地球思想への参照を返します新規に生成したオブジェクトをしなくても、愚かなことをやった上rFunc?(少なくとも聞いたのですがこのバカバカしく.)
更新:以来、皆が同意するrFuncで違法、もうひとつの関連する質問
いバックパスを指すポインター方とのコミュニケーションは、プログラマーは、ポインタをいち削除しそのような場合には?またどのようなコミュニケーションのポインタは削除の時と同じスレッドが別の機能の呼び出し機能しないで下さい、この場合.唯一のコミュニケーションツールを通してこのコメント?そうなずさんな.
注意:すべてのこれまでのアイディアを考えてい分子を鋳型としshared_pimplをコンセプトにした。ばんぶのに十分なポストについて何かがカップルです。
解決
1)新しいオブジェクトを作成している場合は、あなたが参照を返すようにしたいことはありません(#3にご自身のコメントを参照してください。)あなたは、おそらくstd::shared_ptr
またはstd::auto_ptr
によってラップポインタ()を返すことができます。 (あなたはまた、コピーによって返すことができますが、これはnew
演算子を使用してと互換性がありません;それはまた、多型と少し互換性がないのです)。
2)rFunc
はちょうど間違っています。それをしないでください。あなたがオブジェクトを作成するためにnew
を使用した場合は、(必要に応じてラップ)ポインタを通してそれを返します。
3)は、あなたがになっていません。これは、ポインタがためているものです。
<時間>編集(お使いの更新への対応:)それはあなたが記述しているシナリオを想像するのは難しいです。それは、発信者が他のいくつかの(特定の)メソッドを呼び出します一度返されたポインタが無効になる可能性のあると言うことは、より正確になりますか?
私は、このようなAモデルを使用しないことをお勧めするが、あなたは絶対にこれを行う必要がある場合、あなたはあなたのAPIでこれを施行しなければならない、あなたはおそらく間接のレベルを追加する必要がある、あるいは2。例:ラップ実際のポインタを含む参照カウントオブジェクトに実際のオブジェクト。実際のオブジェクトが削除されたときに参照カウントオブジェクトのポインタがnull
に設定されています。これは醜いです。 (そこにそれを行うには良い方法かもしれないが、彼らはまだ醜いかもしれません。)
他のヒント
答えるためにあなたの質問の後半部分(「どのように私は、ポインタはいつでも削除の対象であることを通信しない」) -
これは危険な練習で、あなたが考慮する必要があります微妙な詳細を持っています。それは自然の中で際どいです。
ポインタは、任意の時点で削除することができた場合は、は、あなたがチェックした場合でもので、別の文脈からそれを使用しても安全になることはありません「あなたがまだ有効です?」たびに、それは確認後ほんの少しを削除されることがありますが、あなたが取得する前にそれを使用します。
これらの事を行うための安全な方法は、「弱いポインタ」という概念である - 共有ポインタ(間接の1つのレベルは、いつでも解除することができ)などのオブジェクトが格納されていて、返された値が弱いポインタである必要があり - あなたがしなければならないことを何か<全角>クエリのあなたが使用する前に、あなたはそれを使用した後解放しなければなりません。長尺物として、この方法は、あなたがそれを使用することができ、まだ有効です。
擬似コード(弱い発明し、共有のポインタに基づいて、私は...ブーストを使用していない) -
weak< Animal > animalWeak = getAnimalThatMayDisappear();
// ...
{
shared< Animal > animal = animalWeak.getShared();
if ( animal )
{
// 'animal' is still valid, use it.
// ...
}
else
{
// 'animal' is not valid, can't use it. It points to NULL.
// Now what?
}
}
// And at this point the shared pointer of 'animal' is implicitly released.
しかし、これは複雑で、エラーが発生しやすくなり、そしておそらくあなたの人生は困難になるだろう。私は、可能な場合は単純な設計のために行くお勧めします。
あなたが戻るか、または周りに合格する必要がスライスしないようにするためには、のポインタのオブジェクトへ。基準は、基本的に「永久的に逆参照ポインタ」であること(注
Animal r2 = rFunc();
r2.makeSound();
ここで、R2は、ティンは(コンパイラ生成されたコピーctorのを使用して)インスタンス化されるが、それは残しています 犬の部品オフ。あなたはこのようにそれを行う場合は、スライスは発生しません。
Animal& r2 = rFunc();
しかし、あなたのvFunc()メソッド自体の内部機能スライスを。
私もこの機能を言及します:
Animal& rFunc()
{
return *(new Dog());
}
それは奇妙で危険なのです。あなたは一時的な無名の変数への参照を作成している(犬を間接参照)。これは、ポインタを返すために、より適切です。参照を返すと、通常のリターンメンバ変数などに使用されます。
私は戻ってポインタを渡す場合はどのように私はポインタがこのような場合には削除する彼らではないことをプログラマに伝えるのですか?または代わりにどのように私は、呼び出す関数はそれを保存しないようにポインタが(同じスレッドが異なる機能から)いつでも削除の対象であることを通信します。このような場合にはています。
あなたは本当にその後、それらをすべてのポインタを与えていない、ユーザーを信頼することができない場合は、次の(例えば、あなたがあなたの側でインスタンスのベクトルを持つ整数型のハンドルをバック渡し、Cスタイルのインターフェイスを公開フェンスの、そしてあなたは、ベクターに、最初のパラメータとしてインデックスを整数を受け取り、メンバ関数を呼び出す関数)を公開します。 (私たちは常に「メンバ関数」のような派手なものを持っていなかったことにもかかわらず;)それは昔ながらの方法です。)
それ以外の場合は、適切なセマンティクスを持つスマートポインタを使用してみてください。誰もまともには、これまでそのdelete &*some_boost_shared_ptr;
は良いアイデアだと思います。
がついている機能を返します動物の価値はないのです。
- いかに正しく最も近接することができま読み取れなくなってきた。
あります。私は問題ないわからない参考文献がままでいることを理解する異なる種類の変数をC++ではどのよう new
作品は可能です。C++では、数指定することができ、プリミティブデータ(int,float,double等)、 オブジェクト、またはポインタースーパーコンピュータを用いるプリミティブおよび/またはオブジェクトです。Javaでは、変数のみ可能で、またはプリミティブへの参照オブジェクトです。
C++では、ときに変数を宣言するのに、実際のメモリを割り当てに関連する変数となります。Javaは、明示的に作成を使用したオブジェクトの新的かつ明示的に割り当て、新しいオブジェクトを変数となります。のキーポイントであるにも関わらず、C++、オブジェクトに変数を使用するアクセスには同じものではありませんが、変数のポインタは参考値です。 Animal a;
にとって意味のあるから Animal *a;
とも異なるから Animal &a;
.これに対して互換性の種類はありません互換性があります。
き型 Animal a1
C++.新しい Animal
オブジェクトが作成されます。きタイプ Animal a2 = a1;
, ま二つの変数(a1
や a2
) Animal
オブジェ異なる場所。両方のオブジェクトが同じ値に変更することがその価値を独立になります。Javaの場合、入力同じコードを使い終わる二つの変数は、オブジェクトです。どんお買い上げ時の設定で動のいずれかの変数も、いつもと同じ値とする。
- また、当然の責務の一つのrFuncインターフェースの参照が返され割り当て動物&?(又はその他の意図的に割り当てを参照し、動物、スライスを破棄しての多型.)
ご利用の際は参照でポインタのアクセスでき、オブジェクトの価値をコピーしたいです。ることができるので外部からの巻きブレース場が宣言されたオブジェクト。参考文献として一般に使用されている関数パラメータを返しオブジェクトの個人データのつながりがない人でも、新しいコピーの作成します。通常、ときに受けら参照ではなく、割り当てする活動も実施しています。使用例ではなく、割り当の基準で返される rFunc()
変数には、通常タイプ rFunc().makeSound();
.
であり、既存のユーザーの rFunc()
, いる場合に割り当ての返り値になり、割り当てを参照しています。きのうのではないでしょうか。を割り当てた場合の参照を返される rFunc()
変数として宣言された Animal animal_variable
, まつ Animal
変数は、 Animal
オブジェクト、 Dog
オブジェクトです。の Animal
に関連したオブジェクト animal_variable
は、可能な限りのコピー Dog
オブジェクトによって返された参照 rFunc()
.そんな多様な行動から animal_variable
この変数になる Dog
オブジェクトです。の Dog
オブジェクトによって返された参照が存在するので作成したい new
, ものではなくなったアクセスが漏れます。
- どのように地球思想への参照を返します新規に生成したオブジェクトをしなくても、愚かなことをやった上rFunc?(少なくとも聞いたのですがこのバカバカしく.)
問題は作成できるオブジェクトを生成します。
{ // the following expressions evaluate to ...
Animal local;
// an object that will be destroyed when control exits this block
Animal();
// an unamed object that will be destroyed immediately if not bound to a reference
new Animal();
// an unamed Animal *pointer* that can't be deleted unless it is assigned to a Animal pointer variable.
{
// doing other stuff
}
} // <- local destroyed
すべての new
なC++言語による作物体メモリーされませんので破壊されるまでに言います。も破壊したりしようとするものから、うひとつ忘れてはいけないので作成される。いることを指すポインタ変数
Animal *AnimalPointer;
,
格のポインタを返す new Animal()
で
AnimalPointer = new Animal();
.の破壊に Animal
オブジェクトが終わった時点でできるタイプ delete AnimalPointer;
.
ポイント1:参照を使用しないでください。使用ポインタます。
ポイント2:階層的な分類体系であるあなたは上記の分類と呼ばれているもの。分類法は、オブジェクト指向モデリングのために全く不適切である一種の模範です。お使いのベース動物は、すべての動物を前提としているため、あなたの簡単な例は、のみ動作音がして、何も他に面白いを行うことはできません。
あなたのような、関係を実装しようとした場合、
仮想BOOL動物::食事(動物*その他)= 0;
あなたはそれを行うことはできませんでしょう。事はある:犬は動物の抽象化のサブタイプではありません。分類法の全体のポイントは、パーティションの各レベルのクラスは、新たな興味深い性質を持っているということです。
たとえば:脊椎動物は、バックボーンを持っているし、我々はそれがcartiledgeや骨で作られているかどうかを尋ねることができます..私たちも、無脊椎動物の質問をすることはできません。
は、完全にあなたが犬のオブジェクトを作ることができないことを確認しなければならない、理解しています。結局のところ、それは右の抽象化、ですか? 、そこKelpiesとコリーがあり、個々の犬は、いくつかの種でなければならないので...分類体系は次のようにあなたのように深いようすることができますが、任意の具体的な個人をサポートすることはできません。ファイドは、それはちょうど彼の分類タグだ、のない-ドッグのです。
(私は...動的メモリは、メモリリークを起こし参照に行くとあなたの問題を無視しています)
あなたの分割問題は、動物が抽象基底クラスであるとき、離れて行きます。意味することは、少なくとも一つの純粋仮想メソッドを持っており、直接インスタンス化することはできません。以下は、コンパイラエラーになります:
Animal a = rFunc(); // a cannot be directly instantiated
// spliting prevented by compiler!
が、コンパイラができます:
Animal* a = pFunc(); // polymorphism maintained!
Animal& a = rFunc(); // polymorphism maintained!
このように、コンパイラは一日節約!
あなたはメソッドから多相型を返すようにしたいとヒープ上に割り当てたくないあなたは、そのメソッドのクラスでフィールド作り、何でも、基本クラスのそれへのポインタを返すように機能させることを検討することができればあなたが欲しいです。