目次
はじめに
C++で、関数の中で構造体のデータを利用したい場合、どのようにしてそのデータを関数に渡せばよいでしょうか? C++には、主に3つの方法があり、それぞれにメリットとデメリットがあります。
- 値渡し (Pass by Value): 構造体のコピーを作成して渡す、最もシンプルな方法。
- ポインタ渡し (Pass by Pointer): 構造体のメモリアドレスを渡す、C言語由来の伝統的で効率的な方法。
- 参照渡し (Pass by Reference): 構造体の参照を渡す、C++で推奨される、安全で効率的な方法。
この記事では、これら3つの方法について、それぞれの仕組みと使い方、そして使い分けのポイントを解説します。
3つの渡し方のサンプルコード
このコードは、Product
(商品)構造体を、3つの異なる渡し方をする関数にそれぞれ渡して、同じ結果を表示するものです。
完成コード
#include <iostream>
#include <string>
using namespace std;
struct Product {
int id;
string name;
};
// 1. 値渡し (Pass by Value)
void displayByValue(Product item) {
cout << "ID: " << item.id << ", 商品名: " << item.name << " (値渡し)" << endl;
}
// 2. ポインタ渡し (Pass by Pointer)
void displayByPointer(const Product* p_item) {
cout << "ID: " << p_item->id << ", 商品名: " << p_item->name << " (ポインタ渡し)" << endl;
}
// 3. 参照渡し (Pass by Reference)
void displayByReference(const Product& r_item) {
cout << "ID: " << r_item.id << ", 商品名: " << r_item.name << " (参照渡し)" << endl;
}
int main() {
Product myProduct = {101, "高機能マウス"};
// 各関数を呼び出す
displayByValue(myProduct);
displayByPointer(&myProduct);
displayByReference(myProduct);
return 0;
}
1. 値渡し (Pass by Value)
// 宣言: void displayByValue(Product item);
// 呼出: displayByValue(myProduct);
- 仕組み: 関数を呼び出す際に、構造体
myProduct
の完全なコピーが作成され、それが関数の仮引数item
に渡されます。 - メリット:
- 仕組みがシンプルで分かりやすい。
- 関数内で何をしても、元の
myProduct
には一切影響がありません。
- デメリット:
- 構造体のサイズが大きい場合、**コピーのコスト(時間とメモリ)**が無視できなくなります。
2. ポインタ渡し (Pass by Pointer)
// 宣言: void displayByPointer(const Product* p_item);
// 呼出: displayByPointer(&myProduct);
- 仕組み: 構造体そのものではなく、それが格納されているメモリアドレスだけを関数に渡します。
- メリット:
- 大きな構造体を渡す場合でも、アドレス(通常4バイトか8バイト)を渡すだけなので、非常に高速で効率的です。
- デメリット:
- 呼び出し側はアドレス演算子
&
を、関数側はポインタ*
とアロー演算子->
を使う必要があり、構文が少し複雑になります。 - ポインタが
NULL
である可能性(ヌルポインタ)を考慮する必要があります。
- 呼び出し側はアドレス演算子
3. 参照渡し (Pass by Reference)
// 宣言: void displayByReference(const Product& r_item);
// 呼出: displayByReference(myProduct);
- 仕組み: 内部的にはポインタと似ていますが、関数側では通常の変数と同じように扱える、C++の便利な機能です。
- メリット:
- ポインタ渡しと同様に、コピーが発生しないため非常に効率的です。
- 呼び出し側も関数側も、値渡しとほぼ同じシンプルな構文で記述できます。
- ヌルポインタのような心配がありません。
- デメリット:
- 参照渡しであることを意識しないと、関数内で意図せず元の値を変更してしまう可能性があります。(これを防ぐために、変更が不要な場合は
const
を付けるのが一般的です)
- 参照渡しであることを意識しないと、関数内で意図せず元の値を変更してしまう可能性があります。(これを防ぐために、変更が不要な場合は
まとめ
関数に構造体を渡す3つの方法を解説しました。
方法 | 効率 | 構文のシンプルさ | 安全性 | C++での推奨度 |
値渡し | △ (コピーが発生) | ◎ (最もシンプル) | ◎ (元の値は不変) | △ (小さな構造体のみ) |
ポインタ渡し | ◎ (高速) | △ (構文が複雑) | ◯ | ◯ (C言語との互換性) |
参照渡し | ◎ (高速) | ◎ (シンプル) | ◯ | ◎ (最も推奨) |
結論として、現代のC++では、パフォーマンスと書きやすさのバランスが最も良い「参照渡し (const
付き)」を第一の選択肢として考えるのがベストプラクティスです。