【C++】newとdelete
- C言語でメモリを動的割り当てするときはmalloc()を使用し、メモリを開放するときにfree()を使う
- C++ではnewを使用してメモリを割り当て、deleteを使用して開放する
- new演算子は自動的に十分なメモリを割り当てる
- sizeof()などを使用する必要がない
- new演算子は指定した方のポインタを自動的に返す
- malloc()関数を使用してメモリを当てるような明示的に型キャストは行わなくて良い
- オーバーロードできる
study120.cpp
#include <iostream> using namespace std; class samp { int i, j; public: void set_ij( int a, int b ) { i = a; j = b; } int get_product() { return i*j; } }; int main() { samp *p; p = new samp; if (!p) { cout << "メモリ割り当てエラー\n"; return 1; } p->set_ij( 4, 5 ); cout << "積は:" << p->get_product() << "\n"; return 0; }
$ ./study120 積は:20
study122.cpp
#include <iostream> using namespace std; class samp { int i, j; public: samp( int a, int b ) { i = a; j = b; } int get_product() { return i*j; } }; int main() { samp *p; p = new samp( 6, 5 ); if( !p ) { cout << "メモリ割り当てエラー\n"; return 1; } cout << "積は:" << p->get_product() << "\n"; delete p; return 0; }
$ ./study122 積は:30
動的に割り当てられたオブジェクトに初期値を渡している。
study125.cpp
#include <iostream> using namespace std; class samp { int i, j; public: void set_ij( int a, int b ) { i = a; j = b; } samp() { cout << "コンストラクタの呼び出し\n"; } ~samp() { cout << "デストラクタの呼び出し\n"; } int get_product() { return i*j; } }; int main() { samp *p; p = new samp [10]; if ( !p ) { cout << "メモリ割り当てエラー\n"; return 1; } for ( int i = 0; i < 10; ++i ) p[i].set_ij( i, i ); for ( int i = 0; i < 10; ++i ) { cout << "積[" << i << "]は:" << p[i].get_product() << "\n"; } delete [] p; return 0; }
$ ./study125 コンストラクタの呼び出し コンストラクタの呼び出し コンストラクタの呼び出し コンストラクタの呼び出し コンストラクタの呼び出し コンストラクタの呼び出し コンストラクタの呼び出し コンストラクタの呼び出し コンストラクタの呼び出し コンストラクタの呼び出し 積[0]は:0 積[1]は:1 積[2]は:4 積[3]は:9 積[4]は:16 積[5]は:25 積[6]は:36 積[7]は:49 積[8]は:64 積[9]は:81 デストラクタの呼び出し デストラクタの呼び出し デストラクタの呼び出し デストラクタの呼び出し デストラクタの呼び出し デストラクタの呼び出し デストラクタの呼び出し デストラクタの呼び出し デストラクタの呼び出し デストラクタの呼び出し
コンストラクタ、デストラクタがどのタイミングで呼ばれているかの確認
引用・参考はこちら
【C++】オブジェクトのポインタ
オブジェクトのポインタ
- オブジェクトポインタを使用した演算子は、他のデータ型のポインタ演算と同様に、そのオブジェクト型に関して行われる
- オブジェクトポインタをインクリメントすると次のオブジェクトを指すようになり、デクリメントするとその逆になる。
study112.cpp
#include <iostream> using namespace std; class samp { int a, b; public: samp( int n, int m ) { a = n; b = m; } int get_a() { return a; } int get_b() { return b; } }; int main() { samp ob[4] = { samp( 1, 2 ), samp( 3, 4 ), samp( 5, 6 ), samp( 7, 8 ) }; samp *p; p = ob; for ( int i = 0; i < 4; ++i ) { cout << p->get_a() << ' '; cout << p->get_b() << "\n"; p++; } cout << "\n"; return 0; }
$ ./study112 1 2 3 4 5 6 7 8
Thisポインタ
- すべてのメンバ関数の呼び出し時に自動的に渡されるポインタで、その呼び出しを行ったオブジェクトを指す
ob.f1();
- この場合、f1()関数にはobへのポインタが自動的に渡される
- このポインタをthisという名前で参照する
- フレンド関数には使用不可
study115.cpp
#include <iostream> #include <cstring> using namespace std; class inventory { char item[20]; double cost; int on_hand; public: inventory( char *i, double c, int o ) { strcpy( this->item, i ); this->cost = c; this->on_hand = o; } void show() { cout << this->item; cout << ":$" << this->cost; cout << " 在庫" << this->on_hand << "\n"; } }; int main() { inventory ob( "レンチ", 4.95, 4 ); ob.show(); return 0; }
$ ./study115 レンチ:$4.95 在庫4
これは以下のように略して書くこともできる
study114.cpp
#include <iostream> #include <cstring> using namespace std; class inventory { char item[20]; double cost; int on_hand; public: inventory( char *i, double c, int o ) { strcpy( item ,i ); cost = c; on_hand = o; } void show() { cout << item; cout << ":$" << cost; cout << " 在庫:" << on_hand << "\n"; } }; int main() { inventory ob( "レンチ", 9.45, 4 ); ob.show(); return 0; }
$ ./study114 レンチ:$4.95 在庫4
- 省略形のほうが楽なので、thisを書く人はいないが、原理を理解しておくことは大切。
引用・参考はこちら
【C++】オブジェクトの配列
- オブジェクトは変数を持っており、他の変数と同じ機能と属性を持っている
- オブジェクト配列へのアクセス方法も、ほかの変数配列と同じ
study108.cpp
#include <iostream> using namespace std; class samp { int a; public: samp( int n ) { a = n; } int get_a() { return a; } }; int main() { samp ob[4] = { -1, -2, -3, -4 }; for ( int i = 0; i < 4; ++i ) cout << ob[i].get_a() << ' '; cout << endl; return 0; }
実行
$ ./study108 -1 -2 -3 -4
この例では、-1から-4までの値をobコンストラクタ関数に渡している
samp ob[4] = { -1, -2, -3, -4 };
これは
samp ob[4] = { samp(-1), samp(-2), samp(-3), samp(-4) };
これと同じ。
study109.cpp
#include <iostream> using namespace std; class samp { int a; public: samp( int n ) { a = n; } int get_a() { return a; } }; int main() { samp ob[4][2] = { 1, 2, 3, 4, 5, 6, 7, 8 }; for ( int i = 0; i < 4; ++i ) { cout << ob[i][0].get_a() << ' '; cout << ob[i][1].get_a() << "\n"; } cout << endl; return 0; }
$ ./study109 1 2 3 4 5 6 7 8
このように二次元配列も扱うことができる。
study110.cpp
#include <iostream> using namespace std; class samp { int a, b; public: samp( int n, int m ) { a = n; b = m; } int get_a() { return a; } int get_b() { return b; } }; int main() { samp ob[4][2] = { samp( 1, 2), samp( 3, 4), samp( 5, 6), samp( 7, 8), samp( 9, 10), samp(11, 12), samp(13, 14), samp(15, 16) }; for ( int i = 0; i < 4; ++i ) { cout << ob[i][0].get_a() << ' '; cout << ob[i][0].get_b() << "\n"; cout << ob[i][1].get_a() << ' '; cout << ob[i][1].get_b() << "\n"; } cout << endl; return 0; }
$ ./study110 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
コンストラクタに複数の引数を渡すことができるが、その場合は長い初期化構文を使用しなければならない。
引用・参考はこちら
【C++】フレンド関数
- 関数をクラスのメンバにすることなく、関数からクラスの非公開メンバにアクセスすることができる
- 1つの関数から、2つ以上のクラスの非公開メンバにアクセスしたい時などに使われる。
- クラスの宣言の内部にfriendを先頭につけて関数のプロトタイプを含める
stdudy96.cpp
#include <iostream> using namespace std; class myclass { int n, d; public: myclass( int i, int j ) { n = i; d = j; } friend int isfactor( myclass ob ); }; int isfactor( myclass ob ) { if( !( ob.n % ob.d ) ) return 1; else return 0; } int main() { myclass ob1(10, 2), ob2(13, 3); if ( isfactor( ob1 ) ) cout << "2は10の因数\n"; else cout << "2は10の因数ではない\n"; if ( isfactor( ob2 ) ) cout << "3は13の因数\n"; else cout << "3は13の因数ではない\n"; return 0; }
$ ./study96 2は10の因数 3は13の因数ではない
- isfactor()はmyclassのフレンドなので、myclassの非公開メンバにアクセスできる
- ob.nとob.dの両方を直接参照できる
- クラスメンバアクセス演算子(ドット演算子やアロー演算子)を使用してフレンド関数を呼び出すことはできない
- フレンド関数は継承されない
- 複数のクラスのフレンドになることができる
stdudy98.cpp
#include <iostream> using namespace std; class car; class truck; class car { int passengers; int speed; public: car ( int p, int s ) { passengers = p; speed = s; } friend int sp_greater( car c, truck t ); }; class truck { int weight; int speed; public: truck ( int w, int s ) { weight = w; speed = s; } friend int sp_greater( car c, truck t ); }; int sp_greater ( car c, truck t ) { return c.speed - t.speed; } int main() { int t; car c1(6, 55), c2(2, 120); truck t1(10000, 55), t2(20000, 72); cout << "c1とc2を比較\n"; t = sp_greater( c1, t1 ); if ( t < 0 ) cout << "トラックが速い\n"; else if ( t == 0 ) cout << "乗用車とトラックの速度は同じ\n"; else cout << "乗用車が速い\n"; cout << "\nc2とt2を比較:\n"; t = sp_greater( c2, t2 ); if ( t < 0 ) cout << "トラックが速い\n"; else if ( t == 0 ) cout << "乗用車とトラックの速度は同じ\n"; else cout << "乗用車が速い\n"; return 0; }
$ ./study98 c1とc2を比較 乗用車とトラックの速度は同じ c2とt2を比較: 乗用車が速い
プログラムの通り。
引用・参考はこちら
【C++】関数からオブジェクトの返し
関数にオブジェクトを渡すことができるように、返すこともできる。
#include <iostream> #include <cstring> using namespace std; class samp { char s[80]; public: void show() { cout << s << "\n"; } void set( char * str ) { strcpy( s, str ); } }; samp input() { char s[80]; samp str; cout << "文字列の入力"; cin >> s; str.set(s); return str; } int main() { samp ob; ob = input(); ob.show(); return 0; }
$ g++ -o study92 study92.cpp $ ./study92 文字列の入力:こんにちは こんにちは
study93.cpp
このプログラムはコアダンプになる
#include <iostream> #include <cstring> #include <cstdlib> using namespace std; class samp { char *s; public: samp() { s = "\0"; } ~samp() { if( s ) { free( s ); cout << "sを開放する\n"; } } void show() { cout << s << "\n"; } void set( char *str ) { s = ( char * ) malloc( strlen(str) + 1 ); if ( !s ) { cout << "メモリ割り当てエラー\n"; exit(1); } strcpy( s, str ); } }; samp input() { char s[80]; samp str; cout << "文字列の入力:"; cin >> s; str.set(s); return str; } int main() { samp ob; ob = input(); ob.show(); return 0; }
$ ./study93 文字列の入力:hello sを開放する *** Error in `./study93': double free or corruption (fasttop): 0x0000000001b00440 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7ff642cb97e5] /lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7ff642cc237a] /lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7ff642cc653c] ./study93[0x400cc7] ./study93[0x400bfe] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7ff642c62830] ./study93[0x400a39] ======= Memory map: ======== 00400000-00402000 r-xp 00000000 08:06 14298074 /home/atsuya/study/cpp/study93 00601000-00602000 r--p 00001000 08:06 14298074 /home/atsuya/study/cpp/study93 00602000-00603000 rw-p 00002000 08:06 14298074 /home/atsuya/study/cpp/study93 01aee000-01b20000 rw-p 00000000 00:00 0 [heap] 7ff63c000000-7ff63c021000 rw-p 00000000 00:00 0 7ff63c021000-7ff640000000 ---p 00000000 00:00 0 7ff642939000-7ff642a41000 r-xp 00000000 08:06 13238541 /lib/x86_64-linux-gnu/libm-2.23.so 7ff642a41000-7ff642c40000 ---p 00108000 08:06 13238541 /lib/x86_64-linux-gnu/libm-2.23.so 7ff642c40000-7ff642c41000 r--p 00107000 08:06 13238541 /lib/x86_64-linux-gnu/libm-2.23.so 7ff642c41000-7ff642c42000 rw-p 00108000 08:06 13238541 /lib/x86_64-linux-gnu/libm-2.23.so 7ff642c42000-7ff642e02000 r-xp 00000000 08:06 13238538 /lib/x86_64-linux-gnu/libc-2.23.so 7ff642e02000-7ff643002000 ---p 001c0000 08:06 13238538 /lib/x86_64-linux-gnu/libc-2.23.so 7ff643002000-7ff643006000 r--p 001c0000 08:06 13238538 /lib/x86_64-linux-gnu/libc-2.23.so 7ff643006000-7ff643008000 rw-p 001c4000 08:06 13238538 /lib/x86_64-linux-gnu/libc-2.23.so 7ff643008000-7ff64300c000 rw-p 00000000 00:00 0 7ff64300c000-7ff643023000 r-xp 00000000 08:06 13242862 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ff643023000-7ff643222000 ---p 00017000 08:06 13242862 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ff643222000-7ff643223000 r--p 00016000 08:06 13242862 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ff643223000-7ff643224000 rw-p 00017000 08:06 13242862 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ff643224000-7ff6433a0000 r-xp 00000000 08:06 6686331 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 7ff6433a0000-7ff6435a0000 ---p 0017c000 08:06 6686331 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 7ff6435a0000-7ff6435aa000 r--p 0017c000 08:06 6686331 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 7ff6435aa000-7ff6435ac000 rw-p 00186000 08:06 6686331 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 7ff6435ac000-7ff6435b0000 rw-p 00000000 00:00 0 7ff6435b0000-7ff6435d6000 r-xp 00000000 08:06 13238524 /lib/x86_64-linux-gnu/ld-2.23.so 7ff643782000-7ff643788000 rw-p 00000000 00:00 0 7ff6437d4000-7ff6437d5000 rw-p 00000000 00:00 0 7ff6437d5000-7ff6437d6000 r--p 00025000 08:06 13238524 /lib/x86_64-linux-gnu/ld-2.23.so 7ff6437d6000-7ff6437d7000 rw-p 00026000 08:06 13238524 /lib/x86_64-linux-gnu/ld-2.23.so 7ff6437d7000-7ff6437d8000 rw-p 00000000 00:00 0 7ffe018df000-7ffe01901000 rw-p 00000000 00:00 0 [stack] 7ffe01996000-7ffe01999000 r--p 00000000 00:00 0 [vvar] 7ffe01999000-7ffe0199b000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Aborted (core dumped)
- デストラクタが3回呼び出される
- input()が終了し、ローカルオブジェクトのstrがスコープから外れた時
- input()から返される一時オブジェクトが破棄されるとき
- main()終了時
- 最初のデストラクタが実行されるときにinput()関数で文字列を格納するために割り当てられたメモリが開放される
- すでに開放されているメモリを他の2つが開放しようとする
- 進行中の自動割当システムが破壊される
- したがって、ストラクタやデストラクタがあるときにオブジェクトを返すときは注意が必要
- コピーコンストラクタを使うことで解決できる(こちら)
引用・参考はこちら
【C++】関数へオブジェクトの引き渡し
- 関数に引数としてデータを渡すのと同じように、オブジェクトを渡すこともできる。
study86.cpp
#include <iostream> using namespace std; class samp { int i; public: samp( int n ) { i = n; } void set_i( int n ) { i = n; } int get_i() { return i; } }; void sqr_it( samp o ) { o.set_i( o.get_i() * o.get_i() ); cout << "iのコピーの値は " << o.get_i() << "\n"; } int main() { samp a(10); sqr_it(a); cout << "しかし、a.iはmain()で変更されない:" << a.get_i() << "\n"; return 0; }
$ ./study86 iのコピーの値は 100 しかし、a.iはmain()で変更されない:10
- デフォルトでは 値呼び出し で関数に渡される
- 引数がビット単位でコピーされ、関数ではこのコピーが使われる
study87.cpp
#include <iostream> using namespace std; class samp { int i; public: samp( int n ) { i = n; } void set_i( int n ) { i = n; } int get_i() { return i; } }; void sqr_it( samp *o ) { o->set_i( o->get_i() * o->get_i() ); cout << "iのコピー値は " << o->get_i() << "\n"; } int main() { samp a(10); sqr_it(&a); cout << "今、mainは変更された:" << a.get_i() << "\n"; return 0; }
$ ./study87 iのコピー値は 100 今、mainは変更された:100
- オブジェクトのアドレスを関数に渡すと、関数を呼び出す際に使用した引数を関数内で修正できる
引用・参考はこちら
【C++】オブジェクトの代入
「オブジェクト1=オブジェクト2」のような書き方で代入できる。
study79.cpp
#include <iostream> using namespace std; class myclass { int a, b; public: void set( int i, int j ) { a = i; b = j; } void show() { cout << a << ' ' << b << "\n"; } }; int main () { myclass o1, o2; o1.set( 10, 4 ); o2 = o1; o1.show(); o2.show(); return 0; }
$ g++ -o study79 study79.cpp $ ./study79 10 4 10 4
study80.cpp
このプログラムはコンパイルエラーになる。
#include <iostream> using namespace std; class myclass { int a, b; public: void set( int i, int j ) { a = i; b = j; } void show() { cout << a << ' ' << b << "\n"; } }; class yourclass { int a, b; public: void set( int i, int j ) { a = i; b = j; } void show() { cout << a << ' ' << b << "\n"; } }; int main () { myclass o1; yourclass o2; o1.set( 10, 4 ); o2 = o1; o1.show(); o2.show(); return 0; }
クラスの中身が同じでもクラス名が同じでないと代入できない。
study82.cpp
このプログラムはコアダンプになる。
#include <iostream> #include <cstring> #include <cstdlib> using namespace std; class strtype { char *p; int len; public: strtype( char *ptr) { len = strlen( ptr ); p = ( char * ) malloc( len + 1 ); if( !p ) { cout << "メモリ割り当てエラー\n"; exit(1); } strcpy( p, ptr ); } ~strtype() { cout << "pを開放する\n"; free( p ); } void show() { cout << p << " - 長さ:" << len << "\n"; } }; int main() { strtype s1("This is a test"), s2("I like C++"); s1.show(); s2.show(); s2 = s1; s1.show(); s2.show(); return 0; }
$ g++ -o study82 study82.cpp $ ./study82 This is a test - 長さ:14 I like C++ - 長さ:10 This is a test - 長さ:14 This is a test - 長さ:14 pを開放する pを開放する *** Error in `./study82': double free or corruption (fasttop): 0x0000000000e2ac20 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fe0ad0767e5] /lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7fe0ad07f37a] /lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7fe0ad08353c] ./study82[0x400c64] ./study82[0x400b1b] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fe0ad01f830] ./study82[0x4009b9] ======= Memory map: ======== 00400000-00401000 r-xp 00000000 08:06 14298065 /home/atsuya/study/cpp/study82 00601000-00602000 r--p 00001000 08:06 14298065 /home/atsuya/study/cpp/study82 00602000-00603000 rw-p 00002000 08:06 14298065 /home/atsuya/study/cpp/study82 00e19000-00e4b000 rw-p 00000000 00:00 0 [heap] 7fe0a8000000-7fe0a8021000 rw-p 00000000 00:00 0 7fe0a8021000-7fe0ac000000 ---p 00000000 00:00 0 7fe0accf6000-7fe0acdfe000 r-xp 00000000 08:06 13238541 /lib/x86_64-linux-gnu/libm-2.23.so 7fe0acdfe000-7fe0acffd000 ---p 00108000 08:06 13238541 /lib/x86_64-linux-gnu/libm-2.23.so 7fe0acffd000-7fe0acffe000 r--p 00107000 08:06 13238541 /lib/x86_64-linux-gnu/libm-2.23.so 7fe0acffe000-7fe0acfff000 rw-p 00108000 08:06 13238541 /lib/x86_64-linux-gnu/libm-2.23.so 7fe0acfff000-7fe0ad1bf000 r-xp 00000000 08:06 13238538 /lib/x86_64-linux-gnu/libc-2.23.so 7fe0ad1bf000-7fe0ad3bf000 ---p 001c0000 08:06 13238538 /lib/x86_64-linux-gnu/libc-2.23.so 7fe0ad3bf000-7fe0ad3c3000 r--p 001c0000 08:06 13238538 /lib/x86_64-linux-gnu/libc-2.23.so 7fe0ad3c3000-7fe0ad3c5000 rw-p 001c4000 08:06 13238538 /lib/x86_64-linux-gnu/libc-2.23.so 7fe0ad3c5000-7fe0ad3c9000 rw-p 00000000 00:00 0 7fe0ad3c9000-7fe0ad3e0000 r-xp 00000000 08:06 13242862 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fe0ad3e0000-7fe0ad5df000 ---p 00017000 08:06 13242862 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fe0ad5df000-7fe0ad5e0000 r--p 00016000 08:06 13242862 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fe0ad5e0000-7fe0ad5e1000 rw-p 00017000 08:06 13242862 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fe0ad5e1000-7fe0ad75d000 r-xp 00000000 08:06 6686331 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 7fe0ad75d000-7fe0ad95d000 ---p 0017c000 08:06 6686331 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 7fe0ad95d000-7fe0ad967000 r--p 0017c000 08:06 6686331 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 7fe0ad967000-7fe0ad969000 rw-p 00186000 08:06 6686331 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 7fe0ad969000-7fe0ad96d000 rw-p 00000000 00:00 0 7fe0ad96d000-7fe0ad993000 r-xp 00000000 08:06 13238524 /lib/x86_64-linux-gnu/ld-2.23.so 7fe0adb3f000-7fe0adb45000 rw-p 00000000 00:00 0 7fe0adb91000-7fe0adb92000 rw-p 00000000 00:00 0 7fe0adb92000-7fe0adb93000 r--p 00025000 08:06 13238524 /lib/x86_64-linux-gnu/ld-2.23.so 7fe0adb93000-7fe0adb94000 rw-p 00026000 08:06 13238524 /lib/x86_64-linux-gnu/ld-2.23.so 7fe0adb94000-7fe0adb95000 rw-p 00000000 00:00 0 7ffe7c6d7000-7ffe7c6f9000 rw-p 00000000 00:00 0 [stack] 7ffe7c7ac000-7ffe7c7af000 r--p 00000000 00:00 0 [vvar] 7ffe7c7af000-7ffe7c7b1000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Aborted (core dumped)
- s1とs2を作成するときに、両者とも文字列を格納するためのメモリを割り当てる
- メモリのポインタ変数pに保存される
- strtypeオブジェクトを破棄するときにメモリが開放される
- s1にs2を代入すると、s2はs1と同じメモリを指すようになる
- そのため、s1オブジェクトを2度開放しようとする
- s2のpがメモリを示したポインタは開放されない これらの理由でコアダンプとなる。
そのため、オブジェクトを代入するときは注意が必要。