new 演算子と代入・初期化

001	/****************************/
002	/* new 演算子と代入・初期化 */
003	/*      coded by Y.Suganuma */
004	/****************************/
005	#include <stdio.h>
006	#include <vector>
007	
008	using namespace std;
009	
010	/*****************/
011	/* クラスComplex */
012	/*****************/
013	class Complex
014	{
015		public:
016			int x, y[1], *z;
017			Complex ()
018			{
019				x    = 0;
020				y[0] = 0;
021				z    = new int [1];
022				z[0] = 0;
023			}
024	};
025	
026	/********/
027	/* main */
028	/********/
029	int main()
030	{
031						// 単純変数
032		printf("***単純変数***\n");
033		int a1 = 0;
034		int a2 = a1;
035		a2     = 1234;
036		printf("   a1 %d\n", a1);
037		printf("   a2 %d\n", a2);
038		printf("***単純変数(new)***\n");
039		int *p1 = new int(0);
040		int *p4 = p1;
041		*p4     = 1234;   // p1 が示す値も 1234 になる
042		printf("   p1 %d\n", *p1);
043		printf("   p4 %d\n", *p4);
044						// 複数データ(配列と同等)
045		printf("***配列***\n");
046		int b1[4] = {1, 2, 3, 4};
047		int b2[4];
048		for (int i1 = 0; i1 < 4; i1++)
049			b2[i1] = b1[i1];
050		b2[2] = 200;
051		printf("   b1");
052		for (int i1 = 0; i1 < 4; i1++)
053			printf(" %d", b1[i1]);
054		printf("\n   b2");
055		for (int i1 = 0; i1 < 4; i1++)
056			printf(" %d", b2[i1]);
057		printf("\n***配列(new)***\n");
058		int *p2 = new int [4];
059		for (int i1 = 0; i1 < 4; i1++)
060			p2[i1] = i1 + 1;
061		int *p5 = p2;   // p5 = &p2[0] と同じ
062		p5[2]   = 200;   // *(p5+2) = 200; と同じ
063		printf("   p2");
064		for (int i1 = 0; i1 < 4; i1++)
065			printf(" %d", p2[i1]);
066		printf("\n   p5");
067		for (int i1 = 0; i1 < 4; i1++)
068			printf(" %d", p5[i1]);
069						// クラスのオブジェクト
070		printf("\n***クラスのオブジェクト***\n");
071		Complex c1;
072		Complex c2 = c1;
073		c2.x    = 10;
074		c2.y[0] = 20;
075		c2.z[0] = 30;
076		printf("   c1 x %d y[0] %d z[0] %d\n", c1.x, c1.y[0], c1.z[0]);
077		printf("   c2 x %d y[0] %d z[0] %d\n", c2.x, c2.y[0], c2.z[0]);
078		printf("***クラスのオブジェクト(new)***\n");
079		Complex *p3 = new Complex();
080		Complex *p6 = p3;
081		p6->x    = 10;
082		p6->y[0] = 20;
083		p6->z[0] = 30;
084		printf("   p3 x %d y[0] %d z[0] %d\n", p3->x, p3->y[0], p3->z[0]);   // (*p3).x,・・・ でも可
085		printf("   p6 x %d y[0] %d z[0] %d\n", p6->x, p6->y[0], p6->z[0]);   // (*p6).x,・・・ でも可
086						// STL の vector
087		printf("***STL の vector***\n");
088		vector <int> d1(4, 0);
089		vector <int> d2 = d1;
090		d2[1] = 10;
091		printf("   d1");
092		for (int i1 = 0; i1 < 4; i1++)
093			printf(" %d", d1[i1]);
094		printf("\n   d2");
095		for (int i1 = 0; i1 < 4; i1++)
096			printf(" %d", d2[i1]);
097		printf("\n***STL の vector(new)***\n");
098		vector <int> *p7 = new vector <int> (4, 0);
099		vector <int> *p8 = p7;
100		(*p7)[1] = 10;
101		printf("   p7");
102		for (int i1 = 0; i1 < 4; i1++)
103			printf(" %d", (*p7)[i1]);
104		printf("\n   p8");
105		for (int i1 = 0; i1 < 4; i1++)
106			printf(" %d", (*p8)[i1]);
107		printf("\n");
108						// 領域の開放
109		delete p1;
110		delete [] p2;
111		delete p3;
112		delete p7;
113	
114		return 0;
115	}
		
013 行目~ 024 行目

  クラスの定義です.ここでは,int 型変数 x,int 型の 1 次元配列 y,new 演算子を使用した int 型の 1 次元配列 z から構成される新しい Complex 型の変数が定義されたという程度で理解しておいて下さい.

032 行目~ 037 行目

  int 型の変数 a1,a2 を定義し,a1 は 0 で初期設定し,それを a2 に代入(初期設定)しています.035 行目において,a2 に 1234 を代入していますので,a1 の値は 0,a2 の値は 1234 になっているはずです.a1 と a2 は異なる変数であり,代入は,代入する値をコピーして実行されるわけですから,当然の結果と言えます.032 行目~ 037 行目内の出力文によって,以下に示すように,予想通りの結果が得られます.
	***単純変数***
	   a1 0
	   a2 1234			
038 行目~ 043 行目

  032 行目~ 037 行目とは異なり,p1,p4 はポインタとして定義してあります.039 行目において,int 型のデータが入る領域が確保され( 0 で初期設定),そのアドレス(右図においては 20 番地)が変数 p1 に代入されます.「 * 」は,変数 p1 が,int 型のデータが入る領域を指すアドレスが記憶される変数(ポインタ)であることを表しています.040 行目において,p1 の値がコピーされて p4 に代入されますが,p1 はアドレスですので p1 に記憶されているアドレスが p4 に代入されます.その結果,p1 と p4 は,全く同じ領域を指すことになります(右図参照).

  041 行目は,変数(ポインタ) p4 が指すアドレスに 1234 を代入するという意味になります.p1 の値と p4 の値は等しいので,この記述と「 *p1 = 1234; 」は同じ結果になり,いずれの場合も,確保した領域に値 1234 が記憶されます(下に示す出力結果参照).
	***単純変数(new)***
	   p1 1234
	   p4 1234			
045 行目~ 056 行目

  046 行目において,4 個の int 型データからなる配列 b1 を定義し,その初期設定を行っています.047 行目~ 049 行目では,その配列を別の配列 b2 にコピーしています.「 b2 = b1 」という処理が不可能ですので,b1 の各要素を対応する b2 の各要素に代入しています.050 行目において,b2 の 3 番目の要素の値を変更していますが,単純変数の場合と同様,b1 と b2 は異なる変数ですので,下に示す出力結果から明らかなように,b1 の各要素は,その影響を受けません.
	***配列***
	   b1 1 2 3 4
	   b2 1 2 200 4			
057 行目~ 068 行目

  058 行目~ 060 行目において,4 個分の int 型データが入る領域が確保し,その先頭アドレス(下の図では 20 番地)を変数 p2 に代入し,初期設定を行っています(下の左図).061 行目において,p2 の値のコピーが p5 に代入されますので,p2 と p5 は同じ場所を指すことになります(下の右図).そのため,062 行目のように,p5[2] の値を変更すると p2[2] の値も変化します(図の下に示す出力結果参照).

	***配列(new)***
	   p2 1 2 200 4
	   p5 1 2 200 4			
070 行目~ 077 行目

  071 行目では,Complex クラスのインスタンス(オブジェクト) c1 を生成し,クラス内の変数 x,y,z[0] を,すべて,0 で初期化しています( 017 行目~ 023 行目).072 行目において,Complex クラスのインスタンス(オブジェクト) c2 を生成し,c1 を代入( c1 で初期化)しています.基本的に,c1 の値のコピーが c2 に代入されるだけですので,c2 の値を変更( 073 行目~ 075 行目)しても,変数 c1 の値は変化しないはずです.しかし,下に示す出力結果を見てください.c1 における z[0] の値も変化しています.これは,代入時のコピーによって,変数 z に記憶されているアドレスだけがコピーされ,そのアドレスが指す場所は考慮されないため,c1 と c2 の z は,同じデータを指すことになるからです.
***クラスのオブジェクト***
   c1 x 0 y[0] 0 z[0] 30
   c2 x 10 y[0] 20 z[0] 30			

078 行目~ 085 行目

  Complex クラスのインスタンス(オブジェクト)を記憶できる領域が確保され,そのアドレスが変数 p3 に代入されます( 079 行目).080 行目によって,p3 と p6 が同じ場所を指すことになるため,片方の変数と介して値を変更すれば( 081 行目~ 083 行目),他の変数の値も変化します(下に示す出力結果参照).
***クラスのオブジェクト(new)***
   p3 x 10 y[0] 20 z[0] 30
   p6 x 10 y[0] 20 z[0] 30			
087 行目~ 107 行目

  C++ 標準ライブラリ内の vector クラスを扱った例です.基本的に,Complex クラスのオブジェクトを扱った場合と同じような結果が得られます.
***STL の vector***
   d1 0 0 0 0
   d2 0 10 0 0
***STL の vector(new)***
   p7 1 10 1 1
   p8 1 10 1 1			
109 行目~ 112 行目

  確保した領域を必要としなくなった場合は,delete 演算子によって,確保されたメモリを解放してやる必要があります.ただし,C/C++ においては,ガーベッジコレクションが行われないため,頻繁に大きなサイズの new や delete を繰り返すと,残されたゴミのためメモリが圧迫されることになります.