「newとdelete」の版間の差分
(→概要) |
|||
行16: | 行16: | ||
そのため [[C++]] では、malloc()/free() を基本的に利用しません。 | そのため [[C++]] では、malloc()/free() を基本的に利用しません。 | ||
− | メモリの管理には、[[スマートポインタ]]を利用するのがお勧めです。[[スマートポインタ]] | + | メモリの管理には、[[スマートポインタ]]を利用するのがお勧めです。[[スマートポインタ]]は、メモリの解放忘れを防ぎ、メモリリークを抑制します。 |
== メモリの確保と解放 == | == メモリの確保と解放 == |
2018年4月21日 (土) 22:02時点における最新版
C++ の new 演算子 と delete 演算子は、メモリの動的な確保と解放に使用します。メモリが確保できない場合は、std::bad_allocの例外を投げます。std::nothrowを使用した場合、失敗したときに例外を投げずにNULLが返ります。new演算子を使用する場合には、スマートポインタと併用するのが良いでしょう。
読み方
- new
- にゅー
- delete
- でりーと
目次
概要
new と delete は、 C言語 における malloc() と free() の関係に似ています。 new でメモリを確保した場合、使い終わったら、明示的に delete で解放しなければなりません。 new は、ポインタを返します。
new を呼び出すと、型のコンストラクタが呼び出されます。delete を呼び出すと、デストラクタが呼び出されます。 malloc()/free() を使用した場合、コンストラクタとデストラクタが呼び出されません。 そのため C++ では、malloc()/free() を基本的に利用しません。
メモリの管理には、スマートポインタを利用するのがお勧めです。スマートポインタは、メモリの解放忘れを防ぎ、メモリリークを抑制します。
メモリの確保と解放
int *p = new int(30); // 確保と初期化 *p += 20; cout << *p << endl; delete p; // 解放
配列の確保と解放
delete演算子でメモリを解放する場合には、カギ括弧を忘れずに指定してください。
int *p = new int[10]; // 確保 p[0] = 30; cout << p[0] << endl; delete [] p; // 解放
エラー時のstd::bad_allocをキャッチする
new演算子は、メモリを確保する際に、メモリが不足している場合、例外 std::bad_alloc を投げます。そのため、newを使う場合には、try/catch で例外をキャッチしなければなりません。
#include <iostream> using namespace std; int main (int argc, char *argv[]) { { try { char *p = new char[4096]; delete [] p; } catch (bad_alloc) { cerr << "Memory exhausted\n"; } return 0; }
std::nothrowを使用してエラー時に例外を投げない
デフォルトの動作では、new演算子は、メモリ確保に失敗したときに、std::bad_allocの例外を投げます。new演算子を使用するときに、std::nothrowを指定すると、メモリ不足のときに、例外を投げる変わりにNULLを返します。
char* p = new (std::nothrow) Foobar; if (p==NULL){ // エラー処理 std::cerr << "Failed!" << std::endl; }
ソースコード std_nothrow1.cpp
/* * std_nothrow1.cpp * Copyright (C) 2014 kaoru <kaoru@bsd> */ #include <iostream> // std::cout #include <new> // std::nothrow int main (int argc, char *argv[]) { char* p = new (std::nothrow) char [999999999999999]; if (p==NULL){ std::cout << "Failed!" << std::endl; } else { std::cout << "Succeeded!" << std::endl; delete[] p; } return 0; }
コンパイル
c++ std_nothrow1.cpp -o std_nothrow1
実行例
% ./std_nothrow1 Failed!
std::set_new_handlerでメモリ不足時に指定したハンドラを呼び出す
new演算子は、メモリ不足のときに 以下の振る舞いをします。
set_new_handlerを使用することで、メモリが不足したときに、指定したハンドラ(関数)を呼び出すことができます。
// C++11 new_handler set_new_handler (new_handler new_p) noexcept;
なお、set_new_handlerにNULLを指定して呼び出すと、デフォルトの動作(bad_allocを投げる)に戻ります。
ソースコード set_new_handler1.cpp
#include <iostream> // std::cout #include <cstdlib> // std::exit #include <new> // std::set_new_handler using namespace std; void out_of_store () { cerr << "Memory exhausted\n"; exit (1); } int main(int argc, char const* argv[]) { set_new_handler (out_of_store); try { new char[999999999999999999]; } catch (std::bad_alloc e) { cerr << e.what() << endl; } cout << "done\n"; return 0; }
コンパイル
c++ set_new_handler1.cpp -o set_new_handler1
実行例
% ./set_new_handler1 Memory exhausted
アロー演算子
ポインタでインスタンスをポインタで操作する場合、メンバ変数やメンバ関数のアクセスには、アロー演算子(->)を利用します。
#include <iostream> using namespace std; class Foo { public: int m_i; Foo (int i) :m_i(i) { } ~Foo () {} void show () { cout << m_i << endl; } }; int main (int argc, char *argv[]) { Foo *p = new Foo(3); p->m_i += 20; p->show (); delete p; return 0; }
メモリのアドレスを表示する方法
メモリのアドレスを表示する詳しい方法については、std::outでポインタや変数のアドレスを表示する方法 をご参照ください。
new演算子で確保したメモリのアドレスを画面に表示して確認したい場合には、std::coutとstd::hexを使用します。
int *p = new int(0); cout << hex << p << endl; delete p;
関連項目
- 配置new(placement new, プレースメントnew)
- std::outでポインタや変数のアドレスを表示する方法
- 配列
- boost::array
スマートポインタに関する情報は、以下のページです。