質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

5回答

10035閲覧

delete後のメモリにアクセス出来る?

Atori

総合スコア29

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2016/05/24 19:14

C++のポインタの勉強中にたまたま起こったんですが、
「なんでこれランタイムエラーにならないんだ?」という現象に遭遇しました。
以下ソースコードです。
VisualStudio2015で実行しました。

###該当のソースコード

cpp

1class Hoo 2{ 3 int abc; 4 5public : 6 Hoo() 7 { 8 abc = 10; 9 } 10 11 ~Hoo() 12 { 13 abc = 10; 14 } 15 16 void Hoge() 17 { 18 abc = 100; 19 } 20}; 21 22void main(){ 23 Hoo *pHoo = new Hoo(); 24 delete pHoo; 25 pHoo->Hoge(); // ここでエラーになるのでは? 26}

コメントを入れている場所で、解放済のインスタンスにアクセスしているのでエラーになるかと思ったんですが、
エラーなく実行出来てしまいました。デバッグで見ると、abcの値も100になっていました。

これって正しい挙動なんでしょうか?
ちなみに、もう一回deleteすると解放済なので当然エラーが出ました。

実装的にはアウトだと思うのですが、なんでエラー吐いてくれなかったのかがわかりません。
よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ベストアンサー

そのプログラムは正しくありません。
解放済みのメモリ領域へのアクセスを行った場合どういう挙動になるか定義されていません。エラーが発生する事もありますし、他所で使用中の領域を破壊しつつ動いても規格通りの挙動になります。
これを未定義動作(Undefined behavior)といいます。
プログラマのミスによって発生するエラーのチェックよりそれらを行わない事によって得られる実行速度を重視しているために存在します。
ソフトウェアの脆弱性の原因としてよく見られるbuffer overflowも未定義動作の一つです。どうとでも動くといういい見本ですね。

余談ですが今回の例のように一見正しく動いているように見えて正しくないコードのデバッグは発見し辛く大変なのでclangやgccにはAddressSanitizerという解放済み領域を使用した場合やbuffer overflow発生時にエラーを発生させるデバッグ用の機能が搭載されました。

投稿2016/05/24 19:47

satoren

総合スコア109

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

規格での定めについては他の方の回答の通りです。

以下、規格でなく実装について述べます。
deleteしても処理系が、メモリをOSに返すわけではないので、メモリアクセス例外にはなりません。
これをエラーにするためには、意図的にエラーチェックするコードを組み込む必要があります。これは処理オーバーヘッドがかかり、速度低下に繋がるために、デフォルトではチェックを行わない処理系が主だと思います。処理系によっては、コンパイル時のオプションでこのようなチェックコードを組み込むことも出来ます。

規格で、「未定義」としているのは、処理系作成者に対して、チェックするかどうかの自由を認めていることになります。
また、OSに対して細かい単位でメモリ要求・返却をできるOSでは、細かくOSにメモリを返却して、メモリアクセス例外になるような処理系が無いとも限りません。

投稿2016/05/24 23:59

otn

総合スコア84423

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

これって正しい挙動なんでしょうか?

挙動としては正しいとも正しくないとも言えます。deleteしたオブジェクトにアクセスした場合の動作は「未定義」であり、文字通りどのような結果になるのか定義されていないため、正しく動くように見える場合もあります。
当然、プログラム的には完全に誤りです。

C/C++のポインタによるアクセスでは、その領域がプログラム的に正しいかどうかをチェックしていません。存在するメモリ領域には基本的には制限なくアクセスできます。
deleteでオブジェクトを解放しても、ヒープ領域の管理情報を使用中から未使用に戻しただけで、オブジェクトが割り当てられていた部分の領域自体はそのまま残っているので、deleteしたはずの領域にもアクセスできてしまうのです。逆に言うと、メモリ領域さえ存在すれば、newしなくてもアクセスできてしまいます。

これは簡単に「メモリ破壊」を引き起こす可能性を示すものであり、C++が「難易度の高い言語」と言われる要因の一つですね。

投稿2016/05/24 23:35

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こんにちわ。

たまたまです。メモリが破壊されていない為、pHoo->Hoge();に飛んでも問題ないだけです。
delete で解放するたびに、解放領域をクリアしたりしませんからね。
試しに、delete後すぐに別の何かをnew すれば壊れるかもしれませんね。

投稿2016/05/24 22:29

mugicya

総合スコア1046

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

動作未定義なので、「偶然に意図通りに動く」こともあります。まあ大抵後にバグが発覚して怒られますが。

投稿2016/05/24 21:51

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問