c++ ポインタ変数 参照渡し、と検索しても、
単にポインタ変数を引数にとっている関数の説明か、
ポインタ渡しと、参照渡しの違いについて、しか出てこない。。。
(検索の仕方が悪いかもしれないけど)
C++なら、ポインタ渡しとは別に、参照渡しができるから、
ポインタ変数自体も、参照渡しで関数に渡せば、
呼び出し元も、関数側も、形を変えずに処理できる、
と思ったので、やってみた。
以下試した処理とソースコード。
argvの内容を確認し、myargvに必要なメモリ領域を確保し、
argvの内容をコピーして、その内容を表示する。
表示後、確保したメモリ領域を解放する。
この処理を、指定した回数ループ処理する。
コピーした内容の表示は、ループ処理の1回目のみ行う。
最後にプロセスが使用した、最大メモリ使用量を表示する。
ループの回数を変更しても、メモリ使用量が増えないことを確認する。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <sys/time.h>
#include <sys/resource.h>
void print_resource() {
struct rusage usage;
getrusage(RUSAGE_SELF, &usage);
std::printf("maxrss=%ld KB\n", usage.ru_maxrss);
}
void delete_arg(int &myargc, char** &myargv) {
if (myargc == 0 || myargv == nullptr) {
return;
}
for (int i = 0; i < myargc; ++i) {
delete [] myargv[i];
}
delete [] myargv;
myargc = 0;
myargv = nullptr;
}
void arg_copy(int argc, char** argv, int &myargc, char** &myargv) {
myargc = 0;
myargv = nullptr;
myargv = new char* [argc];
for (int i = 0; i < argc; ++i, ++myargc) {
size_t len = std::strlen(argv[i]);
myargv[i] = new char[len + 1];
std::strcpy(myargv[i], argv[i]);
}
}
int main(int argc, char** argv) {
if (argc < 2) {
return 1;
}
int loop_count = std::atoi(argv[1]);
int myargc;
char** myargv;
for (int i = 0; i < loop_count; ++i) {
arg_copy(argc, argv, myargc, myargv);
for (int index = 0; index < myargc; ++index) {
if (i == 0) {
std::printf("%s\n", myargv[index]);
}
}
delete_arg(myargc, myargv);
}
print_resource();
return 0;
}
動かしてみると、ちゃんと期待する動作をしている。
ループ回数が増えても、メモリ使用量が増大することはなく、
ちゃんと確保、解放を繰り返している。
[root@localhost ~]# g++ --version
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[root@localhost ~]#
[root@localhost ~]# g++ --std=c++11 ./a.cpp
[root@localhost ~]# ./a.out 1 -c /tmp/test.config -o /tmp/out.txt
./a.out
1
-c
/tmp/test.config
-o
/tmp/out.txt
maxrss=828 KB
[root@localhost ~]# ./a.out 10 -c /tmp/test.config -o /tmp/out.txt
./a.out
10
-c
/tmp/test.config
-o
/tmp/out.txt
maxrss=824 KB
[root@localhost ~]# ./a.out 100 -c /tmp/test.config -o /tmp/out.txt
./a.out
100
-c
/tmp/test.config
-o
/tmp/out.txt
maxrss=828 KB
[root@localhost ~]# ./a.out 1000 -c /tmp/test.config -o /tmp/out.txt
./a.out
1000
-c
/tmp/test.config
-o
/tmp/out.txt
maxrss=824 KB
[root@localhost ~]# ./a.out 10000 -c /tmp/test.config -o /tmp/out.txt
./a.out
10000
-c
/tmp/test.config
-o
/tmp/out.txt
maxrss=824 KB
[root@localhost ~]#
ちなみに、
void arg_copy(int argc, char** argv, int &myargc, char** &myargv)
を
void arg_copy(int argc, char** argv, int &myargc, char** myargv)
にすると、もれなくセグメンテーション違反で死ぬ。
もしchar** &myargvではなく、ポインタ変数で頑張るなら、
void arg_copy(int &argc, char** argv, int &myargc, char*** myargv)
にして、呼び出すとき
arg_copy(argc, argv, myargc, &myargv);
にする。
そして、arg_copy内部で、char** myargv_を別に用意して、もろもろ確保した後、
最後に、*myargv = myargv_、というように確保した領域のポインタをコピーする、
というなんだか面倒なことをする必要がある。
もしくは、関数の戻り値として、確保した領域のポインタを返す、とか。
ひとまず、ポインタ変数も、あまり気にせず、参照渡しできた、という話でした。