ROOT/Programing (書きかけ)
ヒストグラムを関数から戻す
- ヒストグラム (TH1D クラスのインスタンス) のポインタを関数から戻す場合、ポインタのポインタを使うか、ポインタの参照を使う。まず、C++ の文法を思い出す。
関数から値を戻す
- 以下のコードを実行しても 200 とは表示されない。func 関数内の int i は main() 内の int j とは別物であり、func で i を変更しても、main 関数内の j には影響しない。関数の引数は、呼び出し元から関数に値を渡すものであり、関数から値を戻すものではない。すなわち、基本的に関数の引数は一方通行のものである。
#include <iostream> void func(int j){ std::cout << j << std::endl; // 100 と表示される j = 200; return; } void main(){ int i = 100; func(i); std::cout << i << std::endl; // 100 と表示され、func 内の変更は反映されない return; }
- 上記のコードを実行すると main 関数内の int i のメモリ領域と func 関数内の int j のメモリ領域が確保される。func が呼び出されるところで main 関数内の int i のメモリ領域にある 100 という値が func 関数内の int j に代入される。func 関数内でこの値を表示することが可能であるが、func 関数内の int j に値を代入しても、 main 関数内の int i には影響しない。
- 関数内で値を変更し、その値を呼び出し元に戻したい場合は、ポインタを関数に渡すか、参照を使う。これで、あたかも関数から値を戻しているような動作を実現できる。
ポインタを渡す
#include <iostream> void func(int* j){ std::cout << *j << std::endl; // 100 と表示される *j = 200; return; } void main(){ int i = 100; func(&i); std::cout << i << std::endl; // 200 とは表示される return; }
- 上記のコードを実行すると main 関数内の int i のメモリ領域が確保されるが、func 関数内の int j はポインタ変数 j のメモリ領域と j に格納される値(アドレス)が指し示す int 型のメモリ領域が確保される(だぶん)。func 関数が呼び出されると、 main 関数内の int i のアドレスが func 関数内のポインタ変数 i に代入される。このポインタ変数が指し示すメモリ領域は、main 内の int i が確保したメモリ領域なので、func 内でこの領域に値を書き込むことは、呼び出し元の int i に値を書き込むことと同値である。すなわち、呼び出し元の変数の値を変更していることになるので、関数が値を戻しているような動作を実現していることになる。
参照を渡す
#include <iostream> void func(int& i){ std::cout << i << std::endl; // 100 と表示される i = 200; return; } void main(){ int i = 100; func(i); std::cout << i << std::endl; // 200 とは表示される return; }
上記のコードを実行すると main 関数内の int i のメモリ領域は確保されるが func 関数の int& j は参照型なので、この型に対するメモリは確保されない。func が呼び出されると int& j = i という操作が行われ func 関数内で i の参照 j を扱うことが可能となる。参照 j は i の別名であり、i と j はメモリを共有 (?) しており、i と j のアドレスは等しい。すなわち j に対する操作は i に対する操作となる。func 関数内で j に値を書き込めば、呼び出し元の i に値を書き込むことと同値である。呼び出し元の変数の値を変更しているので、関数が値を戻しているような動作を実現していることになる。