こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

インスタンス破棄時にメモリが解放されるようにしたい

C++言語でプログラムを作成しています
あるクラスでインスタンス生成時に動的にメモリを割り当てた後
インスタンスが破棄されるまでそれを使用し
インスタンス破棄時に解放するにはどうしたらいいでしょうか

デストラクタで解放処理を実装すると
明示的にデストラクタが呼ばれた際に解放されてしまい
インスタンスが破棄されるまで使用できませんでした

投稿日時 - 2014-11-30 21:22:58

QNo.8842900

すぐに回答ほしいです

質問者が選んだベストアンサー

デストラクタにとって「いかなる理由で呼び出されたのか」を知る方法はありません. 従って「明示的にデストラクタを呼び出しても問題なく, かつ (スコープの外に出るなどの理由で) インスタンスを*本当に*破棄したいときには*その場で*メモリを解放する」などという都合のよい方法は存在しません.

「必要もないのに明示的にデストラクタを呼び出す」ようなやつにはちゃんとした躾をすべきなのです.

投稿日時 - 2014-12-02 23:43:28

お礼

回答ありがとうございます

都合のよい方法はないのですね
別の対処方法を考えてみようと思います


> 「必要もないのに明示的にデストラクタを呼び出す」ようなやつにはちゃんとした躾をすべきなのです.

本当にその通りだと思います
ただし、躾けるべき相手がお金を払ってくれる立場にいると
なかなかうまくいかないものですが、、、

投稿日時 - 2014-12-03 21:36:40

ANo.7

このQ&Aは役に立ちましたか?

15人が「このQ&Aが役に立った」と投票しています

回答(8)

ANo.8

>明示的にデストラクタが呼ばれてしまった場合でも
>リカバリーできるようにしたいのです

そもそも明示的にデストラクタを呼び出した後、デストラクタを含めインスタンスメソッドが正常に呼び出される保証がありませんけど。
#2で既に書いてますけど明示的にデストラクタを呼び出したことによってインスタンスの残骸にしてしまったものに、いったい何を期待してるんですか?
インスタンスの残骸にインスタンスとして動くように期待しても、それは無理です。

投稿日時 - 2014-12-03 02:50:23

お礼

回答ありがとうございます

リカバリーではなく、エラーを返すようにしようと思います。

投稿日時 - 2014-12-03 21:39:33

ANo.6

まず, 「明示的にデストラクタを呼び出したあとで『ふつう』に (= 『ふつうならデストラクタを実行するような方法』で) スコープ外に出る」のは未定義動作. で形のうえでは, 自動変数に対して明示的にデストラクタを呼び出したとしても placement new を使えばいけるような気はするけど, やったことないからなぁ... というか, 自動変数に明示的にデストラクタを呼び出すなんて, やろうと思ったことがないなぁ. 必要性も思い付かんし.

そもそも, どうして「明示的にデストラクタを呼び出す」必要があるんでしょうか?

投稿日時 - 2014-12-02 00:49:56

お礼

回答ありがとうございます

明示的にデストラクタを呼びだす必要があるというより
明示的にデストラクタが呼び出されることがあっても
プログラムが不正な状態にならない(エラーを返すのは良い)ようにしたいのです

エラーを返すだけならサンプルコードを例にすれば
すべてのメソッドにおいてm_aがNULLでないことを確認すればよいかもしれませんが
エラーを返さなくてよい方法を探していました

投稿日時 - 2014-12-02 21:14:19

ANo.5

>では、明示的にデストラクタを呼んだ後
>使用したい場合はcreateなどのコンストラクタに相当するような機能を用意しておき
>使用する側はそれで初期化することが必要なのでしょうか

明示的にデストラクタを呼ぶケースは、placement newを使用したときのためのものですから、#1のお礼に書いてあるようなする事が間違いです。

投稿日時 - 2014-12-01 21:26:14

お礼

回答ありがとうございます

明示的にデストラクタが呼ばれてしまった場合でも
リカバリーできるようにしたいのです

投稿日時 - 2014-12-02 21:15:57

インスタンスが破棄される時にデストラクタが呼ばれる仕様となっています。
インスタンス破棄 と デストラクタを呼ぶ は同じ事ですね。
つまり、
「デストラクタが呼ばれた際に解放されてしまい、インスタンスが破棄されるまで使用できませんでした」
という文章は、
「インスタンスが破棄された際に解放されてしまい、インスタンスが破棄されるまで使用できませんでした」
となっていて、自明となります。
もしかして、プログラム終了まで動的に確保したメモリを使いたいということでしょうか?
そうだとすれば、Formのクローズイベントなどで処理すればいいかもしれないです。
もしくは、「ある特定のインスタンスで動的に確保したメモリを他のインスタンスでも使用しているので、全ての参照がなくなったら破棄したい」という事なら、参照カウントを用意して、デストラクタが呼ばれた際にデクリメントしていって、参照が無くなった時に解法する方法も考えられます。

投稿日時 - 2014-12-01 18:18:40

お礼

回答ありがとうございます

No1のお礼に、補足としてソースコードのサンプルを記載しました

投稿日時 - 2014-12-01 20:57:17

ANo.3

#2です。

補足しておきますが明示的にデストラクタを呼んだ場合は、インスタンスに必要なメモリが確保されてるだけの状態であってインスタンスとしては破棄済みです(だから#2では「インスタンスの残骸」と書いてる)。

投稿日時 - 2014-12-01 02:59:26

お礼

回答ありがとうございます

> インスタンスに必要なメモリが確保されてるだけの状態であってインスタンスとしては破棄済みです

なるほど。
では、明示的にデストラクタを呼んだ後
使用したい場合はcreateなどのコンストラクタに相当するような機能を用意しておき
使用する側はそれで初期化することが必要なのでしょうか

投稿日時 - 2014-12-01 21:02:04

ANo.2

デストラクタを呼び出した後のインスタンスの残骸に何を期待してるんでしょうか。

投稿日時 - 2014-12-01 02:44:39

ANo.1

なにをいっているのかがわからない. 具体的にはどんなコードでどんな不具合があるの?

投稿日時 - 2014-12-01 00:31:24

お礼

回答ありがとうございます

例えば以下のような、コンストラクタでメモリを割り当て
デストラクタでメモリを解放するクラスがあるとします

class Tile
{
public:
  Tile() : m_a(NULL) { m_a = new int; }
  ~Tile() { delete m_a; m_a = NULL; }
  void set(int value) { *m_a = value; }
  int get() const { return *m_a; }
private:
  int* m_a;
};

このクラスのインスタンスを生成して使用する際、
明示的にデストラクタが呼び出されると、
インスタンスが破棄されていなくても使用できなくなります。

void use()
{
  {
    Tile tile;

    tile.set(10);
    printf("%d\n", tile.get());

    tile.~Tile(); // 明示的なデストラクタ呼び出し。

    tile.set(10); // 動作しない
    printf("%d\n", tile.get()); // 動作しない
  } // ここでインスタンスが破棄され、2回目のデストラクタが呼び出される。
}

デストラクタが呼び出された時ではなく、
インスタンスが破棄されたときにメモリを解放するにはどうしたらいいでしょうか。

投稿日時 - 2014-12-01 20:54:56

あなたにオススメの質問