2.2.2. 配列をヒープ領域上に動的に割り当てる例

2つ目の例では配列データは動的に割り当てます。 そのためdata1,data2の配列の定義はなくなっています。 その代わりにmain関数の中で配列を動的に割り当てています。

一つ目の例と全く同じ関数 set_dummy_data, copy_data, print_data が登 場します。

main関数を見てみます。

36int main(int argc, const char *argv[])
37{
38    std::cout << "s002\n";
39
40    // メモリをヒープ上に獲得する。
41    double *parray1;
42    double *parray2;
43    try {
44        parray1 = new double[N_SIZE];
45        parray2 = new double[N_SIZE];
46    } catch (const std::bad_alloc &exp) {
47        std::cerr << "Out of memory\n";
48        return EXIT_FAILURE;
49    }

doubleへのポインタ型の変数 parray1, parray2 を用意しています。 そして、 try { ... } catch { ... } 構文の中で値を設定しています。

try 節の処理の途中のどこか、関数呼び出しをしている先であっても、そのどこかで throw文が実行されると、処理がそこで中断されて、catch節に飛び込みます。この例で は、メモリ割り当ての new 演算子の中にthrow文が入っています。メモリ不足によりnew が失敗した場合に、throw文で処理を中断するのです。

throw文では、catch節にデータを渡すことができます。失敗の種類や原因を伝えるために 使われます。そのデータのことを例外(exception)と呼びます。この例だと std::bad_alloc 型の例外が throw されます。

メモリが獲得できた場合には、catchには行かずにそのまま処理が進みます。 double型の 配列領域を new 演算子で獲得して parray1, parray2 に記録します。

失敗した場合、 main 関数から return することでプログラムを終了させています。

プログラムでやろうとしていたことに成功して終了する場合(正常終了)の場合には main の戻り値は EXIT_SUCCESS とします。異常終了の場合にはここでやっているように EXIT_FAILURE とします。

50    // newでとったメモリの初期値は不定なので初期化は必須。
51    // ここでは見初期化のまま表示している。
52    std::cout << "Before initialization\n";
53    print_data(parray1, N_SIZE);
54
55    // parray1はポインタ変数なので
56    // 受ける側のdoubleのポインタにそのまま代入できる。
57    set_dummy_data(parray1, N_SIZE);
58    std::cout << "After initialization\n";
59    print_data(parray1, N_SIZE);
60
61    copy_data(parray2, parray1, N_SIZE);
62    std::cout << "After array copy\n";
63    print_data(parray2, N_SIZE);
64
65    // return allocated memory to OS
66    // new に成功した場合にのみ delete を呼ぶこと。
67    delete [] parray1;
68    delete [] parray2;
69
70    return EXIT_SUCCESS; // exit status code 0
71}

main 関数の残りでは、例1の時と同じ関数に対して、配列変数の代わりにdoubleのポ インタ変数を渡しています。

全体のソースを以下に示します:

 1// s002: dynamically allocated array
 2//
 3#include <iostream>
 4
 5const int N_SIZE = 10;
 6
 7// same functions as s001.cpp
 8
 9// function to set dummy data to the array
10void set_dummy_data(double *d, int n)
11{
12    for (int i = 0; i < n; i++) {
13        d[i] = static_cast<double>(i) / static_cast<double>(n);
14    }
15}
16
17void copy_data(double *dest, const double *src, int n)
18{
19    for (int i = 0; i < n; i++) {
20        dest[i] = src[i];
21    }
22}
23
24void print_data(const double *d, int n)
25{
26    std::cout << "[";
27    for (int i = 0; i < n; i++) {
28        std::cout << d[i];
29        if (i < n - 1) {
30            std::cout << ", ";
31        }
32    }
33    std::cout << "]\n";
34}
35
36int main(int argc, const char *argv[])
37{
38    std::cout << "s002\n";
39
40    // メモリをヒープ上に獲得する。
41    double *parray1;
42    double *parray2;
43    try {
44        parray1 = new double[N_SIZE];
45        parray2 = new double[N_SIZE];
46    } catch (const std::bad_alloc &exp) {
47        std::cerr << "Out of memory\n";
48        return EXIT_FAILURE;
49    }
50
51    // newでとったメモリの初期値は不定なので初期化は必須。
52    // ここでは見初期化のまま表示している。
53    std::cout << "Before initialization\n";
54    print_data(parray1, N_SIZE);
55
56    // parray1はポインタ変数なので
57    // 受ける側のdoubleのポインタにそのまま代入できる。
58    set_dummy_data(parray1, N_SIZE);
59    std::cout << "After initialization\n";
60    print_data(parray1, N_SIZE);
61
62    copy_data(parray2, parray1, N_SIZE);
63    std::cout << "After array copy\n";
64    print_data(parray2, N_SIZE);
65
66    // return allocated memory to OS
67    // new に成功した場合にのみ delete を呼ぶこと。
68    delete [] parray1;
69    delete [] parray2;
70
71    return EXIT_SUCCESS; // exit status code 0
72}

Download the source code

実行例を示します

% ./s002
s002
Before initialization
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
After initialization
[0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
After array copy
[0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]