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}
実行例を示します
% ./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]