構造体(C++)は、関数の引数として渡したり、戻り値として返したりできる。

引数として渡す

構造体は値渡し参照渡しもできる。

const 参照で渡す

コピーのコストを避けたい場合や、読み取り専用で扱いたい場合は、const 参照で渡すことが多い。

#include <iostream>
 
struct Employee
{
    int id {};
    int age {};
    double wage {};
};
 
void printEmployee(const Employee& employee)
{
    std::cout << "ID:   " << employee.id << '\n';
    std::cout << "Age:  " << employee.age << '\n';
    std::cout << "Wage: " << employee.wage << '\n';
}
 
int main()
{
    Employee joe { 14, 32, 24.15 };
    printEmployee(joe);
}

値渡しで渡す

構造体が小さく、コピーが安い場合は値渡しも自然である。 値渡しでは、関数内で受け取った引数は呼び出し元とは別オブジェクトになる。

struct Point
{
    double x {};
    double y {};
};
 
void translate(Point p)
{
    ++p.x;
    ++p.y;
}

この場合、translate() の中で p を変更しても、呼び出し元のオブジェクトは変わらない。

戻り値として返す

構造体も、関数の戻り値として普通に返せる。

struct Point3d
{
    double x {};
    double y {};
    double z {};
};
 
Point3d getZeroPoint()
{
    return { 0.0, 0.0, 0.0 };
}

return { 0.0, 0.0, 0.0 }; のように書くと、戻り値の型 Point3d に合わせて一時オブジェクトが作られて返される。

戻り値で返してもよい理由

構造体を値で返すとコピーが重そうに見えるが、C++ではコピー省略ムーブセマンティクスにより、効率よく返せることが多い。 そのため、単に「構造体だから戻り値で返すべきではない」とは限らない。

Point3d makePoint(double x, double y, double z)
{
    return { x, y, z };
}

参照を返す場合の注意

構造体への参照を返すこと自体はできるが、ローカル変数への参照を返してはいけない。

Point3d& getBadPoint()
{
    Point3d p { 0.0, 0.0, 0.0 };
    return p; // ダングリング参照
}

このような参照は、関数終了時に参照先オブジェクトが破棄されるため危険である。

補足

  • 読み取り専用の大きめの構造体は const 参照が使いやすい
  • 小さくてコピーが安い構造体は値渡しも十分有力
  • 新しい構造体を作って返す設計では、戻り値で返すほうが自然なことが多い

関連

参考