伝統的なポインタを使ってnew
で何かを割り当てたときは、C++でdelete this
と言うことができます。実際には、それを注意深く扱うのが良い方法であることも知っています。オブジェクトがstd::shared_ptr
で保持されている場合、delete this
と言うことができますか?そして、デストラクタを呼び出すべきですよね?あなたにアイデアを伝えるために、私は船がミサイルを撃つことができるゲームを作っています。ミサイルを自分自身で削除したいのです。"delete this"をstd :: shared_ptrで割り当てられたオブジェクトに置き換えますか?
答えて
いいえ、オブジェクトの寿命はshared_ptr
のホルダーによって決定されるため、オブジェクト自体が死ぬかどうかを判断できません。あなたがそうするならば、最後にshared_ptr
が死んだときにはダブル が削除されます。私が提供できる唯一の解決策は、あなたの設計を再考することです(最初はshared_ptr
が必要ではなく、ミサイルはおそらく値やプールされたオブジェクトかもしれません)。
ミサイル自体を削除するには、ミサイル自体を所有しているか、少なくともミサイルの所有権を他人と共有する必要があります。 shared_ptr
がミサイルにあると言っているので、あなたは既にミサイルの所有権を共有する複数のオブジェクトを持っていると仮定しています。
ミサイルはshared_ptr
を自分自身に持っていて、それ自体の所有権を共有することは可能です。しかし、これは常に周期的な所有権パターンを作り出します。ミサイルのshared_ptrデータメンバーが参照する限り、参照カウントはゼロに決して落ちることはありません。したがって、ミサイルはリークされます。
あなたは外部のオブジェクトやイベントでミサイルに自分自身を削除するよう指示することができますが、その点が何であるか分かりません。ミサイルに自分自身を削除するように伝えるには、その通信はshared_ptr
を介して行われなければなりません。その後、削除することは実際に起こりません。shared_ptr
はミサイルを運ぶことができます。
はい、可能です。いいえ、私はそれが良い考えだとは思わない。それは私にメモリリークが発生する傾向があり、実際に価値を追加しません。しかし、好奇心のために、ここにあなたがそれを行うだろうかです:
#include <iostream>
#include <memory>
class missile
: public std::enable_shared_from_this<missile>
{
std::shared_ptr<missile> self_;
public:
missile()
{}
~missile() {std::cout << "~missile()\n";}
void set_yourself()
{
self_ = shared_from_this();
}
void delete_yourself()
{
if (self_)
self_.reset();
}
};
int main()
{
try
{
std::shared_ptr<missile> m = std::make_shared<missile>();
m->set_yourself();
std::weak_ptr<missile> wp = m;
std::cout << "before first reset()\n";
m.reset();
std::cout << "after first reset()\n";
// missile leaked here
m = wp.lock();
m->delete_yourself();
std::cout << "before second reset()\n";
m.reset(); // missile deleted here
std::cout << "after second reset()\n";
}
catch (const std::exception& e)
{
std::cout << e.what() << '\n';
}
}
投票が必要かどうかわかりません。解決策は正確で斬新ですが、問題は間違っています。 –
どのようにメモリリークがありますか? 'wp'は期限切れではありません。生ポインタを扱うときとまったく同じ責任があります。それが自分自身を削除している間ミサイルを使用している場合は、あなたの足元から引き出した靴を持っていないボーナスで。 –
@エミリーL:メモリリークが起こりやすいと言いました。ミサイルに自分自身を削除するよう伝えるのを怠ると、それが漏れる。この例は、 'delete_yourself'を呼び出さずにすべての外部所有者を削除することによって証明しています。この例では、外部所有者を再設定し、ミサイルに自分自身を削除するように指示し、外部所有者が所有権を放棄すると削除されます。私。なぜ外部のオーナーがいないのですか?より一般的なイディオムは、ミサイルが自分自身に 'weak_ptr'を維持し、その' weak_ptr'を使って外部エンティティに強力な所有権を渡すことです。 –
を私はレイトショーのだが、私はちょうど今、この自分自身をやりたいと思っに走ったし、それが「であることに気づい知っ種類・オブ可能ですが、あなたはいくつかのことをする必要があります。
ハワードの答えは正しい軌跡ですが、元のshared_ptr
の構築をクライアントに委ねてはいけないので、マークを忘れてしまいます。これは、メモリリークのリスクを開放するものです。代わりに、構造体をカプセル化し、弱いポインタのみを許可する必要があります。削除されたオブジェクトを参照しているすべてのMissilePtr
が満了する付加的な利点を有するdelete this
として意味的に同じ効果をもたらすdie()
を呼び出す
class Missile{
private:
Missile(...){ }; // No external construction allowed
Missile(const Missile&) = delete; // Copying not allowed
void operator = (const Missile&) = delete; // -||-
std::shared_ptr<Missile> m_self;
public:
template<typename... Args>
static MissilePtr makeMissile(Args... args){
auto that = std::make_shared<Misile>(args...);
that.m_self = that; // that holds a reference to itself (ref count = 2)
return that; // 'that' is destroyed and ref-count reaches 1.
}
void die(){
m_self.reset();
}
...
};
typedef std::weak_ptr<Missile> MissilePtr;
void useMissile(MissilePtr ptr){
auto missile = ptr.lock(); // Now ptr cannot be deleted until missile goes out of scope
missile->die(); // m_self looses the reference but 'missile' still holds a reference
missile->whatever(); // Completely valid. Will not invoke UB
} // Exiting the scope will make the data in missile be deleted.
:ここ
は一例です。また、MissilePtr
のいずれかがthis
にアクセスするために使用されている場合、そのアクセスに使用された一時的なstd::shared_ptr
が破壊されるまで削除が遅延され、生涯の頭痛を軽減します。
しかし、必ず少なくとも1つを常にMissilePtr
にし、ある時点でdie()
を呼び出してください。そうしないと、メモリリークが発生します。ちょうどあなたが普通のポインタを使っているのと同じです。
この質問はかなり古いですが、同様の問題がありました(このケースでは、弱いポインタを共有できる一方で、ライフサイクルを管理しなければならない「リスナー」オブジェクト)、解決策を提示していませんでした私のため、私は仮定して、私が見つけた解決策を共有していますその:
- オブジェクトを使用すると、shared_ptrのは、同様の ソリューションです必要がある場合、それは(自身のライフサイクルだ、ひいては share_ptrを共有することはありませんが、weak_ptrを管理します+ use_shared_from_thisはそれを行うことができます)。
- RAIIを破る悪い考えであるので、我々はそれを行うことはありません。私たちは アドレスここでメンバーshare_ptrを含有するものとして、オブジェクト 自身が所有するshared_ptrを持っていることの問題が何であるかは に、二重のコールにつながります(通常は オブジェクト破棄時に1回、自己 にshared_ptrメンバーが含まれていた場合には2回目に呼び出されます)、デストラクタが2回呼び出されるときに、オブジェクトの破棄と通常はクラッシュ(または少なくとも定義されていない の動作)
コード:
#include <memory>
#include <stdio.h>
using std::shared_ptr;
using std::weak_ptr;
class A {
struct D {
bool deleted = false;
void operator()(A *p) {
printf("[deleter (%s)]\n", p, deleted ? "ignored":"deleted");
if(!deleted) delete p;
}
};
public: shared_ptr<A> $ptr = shared_ptr<A>(this, D());
public: ~A() {
std::get_deleter<A::D>($ptr)->deleted = true;
}
public: weak_ptr<A> ptr() { return $ptr; }
};
void test() {
A a;
printf("count: %d\n", a.ptr().lock().use_count());
printf("count: %d\n", a.ptr().use_count());
}
int main(int argc, char *argv[]) {
puts("+++ main");
test();
puts("--- main");
}
出力:
$ g++ -std=c++11 -o test test.cpp && ./test
+++ main
count: 2
count: 1
[deleter (ignored)]
--- main
shared_ptrの削除手段がスタックに割り当てられたオブジェクトに対して呼び出されることはありませ飽きないはずですので、それは通常のオブジェクトの破壊でない場合には、それだけでバイパス削除(既定のオブジェクトデストラクタが既に呼び出されているので、この点まで到達しました)。
- 1. レールでparamsハッシュを割り当て/置き換えます。
- 2. 代入演算子でのstd :: shared_ptrの割り当て
- 3. shared_ptrに割り当てる方法はありますか?
- 4. deleteを呼び出す前に動的に割り当てられたオブジェクトが削除されましたか?
- 5. ヒープに割り当てられたオブジェクト
- 6. ヒープ割り当てオブジェクトのデータメンバーは、ヒープまたはスタックに割り当てられますか?
- 7. cssで割り当てられた幅の値をブラウザが置き換えるのはなぜですか?
- 8. C++ 11のshared_ptrの割り当て
- 9. 関数にshared_ptrを割り当てます。
- 10. スカラーに割り当てられた値ではなく、文字列を置き換える正規表現
- 11. C++でshared_ptrをC++ 11(std :: shared_ptr)に割り当てる:shared_ptrを一時変数に初期化するのはまだ悪いですか?
- 12. 削減呼び出し、与えられたヒープ割り当てられたオブジェクト
- 13. C++のメモリ割り当てnew []とdelete []
- 14. 割り当てられたオブジェクトの再割り当ての問題
- 15. 割り当てられたアクセスアプリケーションは、Ctrl + Alt + Deleteを押したときに終了します。
- 16. 内部メモリが既にヒープに割り当てられている場合、オブジェクトのメモリをヒープに割り当てる必要がありますか?
- 17. 動的に割り当てられたオブジェクトのGetElementID
- 18. $ thisを新しいクラスインスタンスに割り当てることはできますか?
- 19. Doxygenがstd :: shared_ptrまたはstd :: mapを認識できるか
- 20. std :: vectorはどのようにオブジェクトを割り当てますか?
- 21. 以前に割り当てられたオブジェクトの問題のリリース
- 22. iPhone setDelegateを以前に割り当てられたオブジェクト
- 23. スタックに割り当てられたストレージを使用するstd準拠のstringstream?
- 24. ランダムに割り当てられたボタン
- 25. 割り当てられたアドレスで構造をインスタンス化する(割り当て割り当て)
- 26. gcnewに割り当てられたオブジェクトでは、いつ削除する必要がありますか?
- 27. iphoneに割り当てられたオブジェクトの潜在的なリーク
- 28. Sinon:スタブとオブジェクト全体を置き換えて新しいオブジェクトに置き換えます
- 29. 動的に割り当てられた配列のstd :: vectorを作成する方法はありますか?
- 30. ハイバーネーションアノテーションに割り当てられたジェネレータクラス
オブジェクトを削除するには、 'delete this'を使用するのが良い方法ではありません。あなたがそれを慎重に扱わなければならないという事実は、それを示すのに十分です。それは生涯管理を手配する間違いやすい方法です。 – bames53