3

Items のベクトルがあるとします。

vector<Item*> items; //{item1, item2, item3}

次に、コードの他の部分で、

items[1]->suicide();

suicide関数は次のとおりです。

void Item::suicide()
{
   delete this;
}

ベクターサイズとは何itemsですか?現在の配置はどうなっていますか?こんなことしていいの?

編集(追加の質問をしてもよろしいですか?): 出力の目的の配置が{item1, item3}、サイズが2で、ダングリング ポインターがない場合、(それ自体から) 自己破壊的な方法でそれを行う方法はitem2?

編集2:すべての回答をありがとう!素晴らしい。だから私は最終的に決定し、オブジェクトの外からそれを行う方法を見つけました。なぜなら、それは悪い習慣であり、不必要に複雑だったからです

4

7 に答える 7

6

アイテムのベクター サイズとは何ですか。また、現在の配置はどうなっていますか? 同じ。関数呼び出しは、ベクトルの内容もサイズもまったく変更しません。ポインタが指しているメモリを解放するだけです。

これをしても大丈夫ですか?より正確には、それは合法的な C++ ですか? はい。それは良いスタイルのプログラミングですか?いいえ、後者について詳しく説明しましょう。

  • 懸念事項を分離する必要があります: メモリ管理の責任者は誰ですか? クラスのコンテナかユーザーか、ItemそれともクラスItem自体か?

  • 通常、コンテナーまたはユーザーは何が起こっているかを知っているため、これを行う必要があります。

  • それを行う方法は何ですか?最新で安全な C++ コードでのメモリ管理は、ほとんどの場合、 や などのスマート ポインターstd::shared_ptrと やなどstd::unique_ptrのコンテナーを使用して行われます。std::vectorstd::map

  • クラスItemが値型の場合 (つまり、単純にコピーでき、仮想関数に関してポリモーフィックな動作がないことを意味します)、std::vector<Item>代わりにコードに使用します。コンテナから要素が削除されるとすぐに、デストラクタが自動的に呼び出されます。コンテナがそれを行います。

  • クラスItemにポリモーフィックな動作があり、基本クラスとして使用できる場合は、代わりにstd::vector<std::unique_ptr<Item>>orを使用し、オーバーヘッドが少ないため、ソリューションを優先します。オブジェクトの参照を停止するとすぐに、使用しているスマート ポインターのデストラクタによって自動的に削除されます。もう (ほとんど) メモリ リークを心配する必要はありません。std::vector<std::shrared_ptr<Item>>std::unique_ptr

  • メモリ リークを発生させる唯一の方法はstd::shared_ptrs、相互に循環的に参照するオブジェクトを含むことです。を使用std::unique_ptrsすることで、このようなトラブルを防ぐことができます。別の方法はstd::weak_ptrs.

結論: function を提供しないでくださいsuicide()。代わりに、呼び出し元のコードのみに責任を負わせてください。標準ライブラリ コンテナーとスマート ポインターを使用して、メモリを管理します。

編集:あなたの編集の質問について。書くだけ

items.erase( items.begin() + 1 );

std::vectorこれは、値またはポインターのすべてのタイプで機能します。std::vectorおよび C++ 標準ライブラリの適切なドキュメントは、こちら にあります

于 2013-06-10T09:07:37.593 に答える
5

自殺メンバーはベクトルを変更しません。したがって、ベクトルには無効なポインターである要素が含まれており、形式的には無効なポインターを使用して多くのことを行うことはできません。コピーまたは比較することは未定義の動作です。したがって、ベクトルのサイズ変更を含め、それにアクセスするものはすべて UB です。

正式には UB の場合はすべてのアクセスですが、ポインターを逆参照しない限り、実装が奇妙に動作しない可能性が高くなります。アクセス UB を作成する根拠は、無効なポインターをレジスターにロードすることができるマシンです。 x86 はそれらの一部ですが、このモードで動作する広範な OS については知りません。

于 2013-06-10T08:41:48.190 に答える
1

あなたの関数は、ベクトルでsuicide何もしません。それについて何かを知っていることは言うまでもありません。Itemsしたがって、ベクトルの観点からは、関数を呼び出しても何も変わらず、それを行っても問題ありません。

于 2013-06-10T08:33:56.553 に答える
1

ポインターが無効になります。それだけです。再発しないように注意する必要がありますdeletevector<Item*>単独では要素を削除しません。

于 2013-06-10T08:34:19.570 に答える
0

ベクトルはアイテムのデストラクタを呼び出さないため、ポインターのベクトルの場合は問題ありません。ただし、どのポインターがまだ有効であるかをどうにかして知る必要があります。

値によってベクトルにアイテムを格納している場合、アイテムのデストラクタを呼び出すことは問題ありません。ベクターが破棄またはクリアされると、アイテムのデストラクタが再度呼び出され、アプリケーションがクラッシュします。

于 2013-06-10T08:38:41.683 に答える
0

うわー、あなたはタイプミスをしているようです。それはvector<Item *> Items; あなたの質問に関して:

  1. ベクトル Items のサイズは変更されません。つまり、Item オブジェクトへの 3 つのポインタがまだあります。
  2. ベクトルの内容は変更されません: Items[1]->suicide() の前、Items[0] = 0x000001、Items[1] = 0x000005、Items[2] = 0x000009、Items[1]->suicide() の後、アイテム[0] = 0x000001、アイテム[1] = 0x000005、アイテム[2] = 0x000009
  3. そうすることは間違いなくOKです。

その上、ベクトルはそのメモリを自動的に管理します。容量が十分でないときにいくつかの要素をそれにプッシュすると、より大きなスペースが再割り当てされますが、いくつかの要素をポップしたり、いくつかの要素を消去したりすると、冗長メモリは決して与えられませんシステムに。

のコードはItems[1]->sucide()、ポインター Items[1] が保持またはポイントするメモリをシステムに返すだけで、ポインター自体には何もしません。Items[1] は同じ値を保持しますが、安全でない領域を指します。

予期せず、デザイン パターンを作成しました。クラスをデザインする必要があり、そのクラスのオブジェクトをヒープにのみ割り当てることを許可するとします。次のコードを記述できます。

class MustOnHeap
{
   private:
      ~MustOnHeap() { // ...}
   public:
      void suicide() { delete this;}

};

次に、デストラクタがプライベートであるため、クラスはスタックに割り当てられたインスタンスを持つことができず、オブジェクトがそのスコープを出るときにコンパイラがデストラクタの呼び出しを調整する必要があります。したがって、それらをヒープに割り当ててから、MustOnHeap* p = new MustOnHeap;明示的に破棄する必要があります: p->suicide();

于 2013-06-10T08:54:10.227 に答える