9
7

More than 5 years have passed since last update.

ポインタ変数を参照渡し

Posted at

c++ ポインタ変数 参照渡し、と検索しても、
単にポインタ変数を引数にとっている関数の説明か、
ポインタ渡しと、参照渡しの違いについて、しか出てこない。。。
(検索の仕方が悪いかもしれないけど)

C++なら、ポインタ渡しとは別に、参照渡しができるから、
ポインタ変数自体も、参照渡しで関数に渡せば、
呼び出し元も、関数側も、形を変えずに処理できる、
と思ったので、やってみた。

以下試した処理とソースコード。

argvの内容を確認し、myargvに必要なメモリ領域を確保し、
argvの内容をコピーして、その内容を表示する。
表示後、確保したメモリ領域を解放する。

この処理を、指定した回数ループ処理する。
コピーした内容の表示は、ループ処理の1回目のみ行う。

最後にプロセスが使用した、最大メモリ使用量を表示する。

ループの回数を変更しても、メモリ使用量が増えないことを確認する。

a.test

#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_、というように確保した領域のポインタをコピーする、
というなんだか面倒なことをする必要がある。

もしくは、関数の戻り値として、確保した領域のポインタを返す、とか。

ひとまず、ポインタ変数も、あまり気にせず、参照渡しできた、という話でした。

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7