「newとdelete」の版間の差分

提供: C++入門
移動: 案内検索
(概要)
 
行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演算子は、メモリ不足のときに 以下の振る舞いをします。

  • std::bad_allocの例外を投げます
  • std::nothrowを指定するとNULLを返します

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;

関連項目

スマートポインタに関する情報は、以下のページです。