C++ 基礎からマスターまで — 第7回
const、参照、ポインタの違い
本ブログ作成文は、講義を目指して製作されました。 また、作成された文章の情報も間違っている可能性がありますので、ご注意ください。
関数にオブジェクトを渡すときは、値、参照、ポインタのいずれを使用するかを決定する必要があります。 一見すると似ていますが、コピーと修正の可能性に違いがあります。
値と参照
void PrintItem(Item item); //値を渡す
void UpgradeItem(Item& item); //参照渡し
void PrintItem(const Item& item); //定数参照渡し
値として渡すと、関数は別々のコピーを受け取ることができます。 小さいint型であれば特に問題はありませんが、文字列と複数のメンバーを持つオブジェクトであればコピーが不要になることがあります。
Item&はオリジナルのエイリアスです。関数内で修正すると、元も修正される。 const Item&コピーは避けながら元の修正は防ぐ。読み取りのみするオブジェクトを渡すときによく使う形だ。
class Monster
{
public:
int GetHealth() const
{
return health;
}
const std::string& GetName() const
{
return name;
}
private:
int health = 100;
std::string name = "Slime";
};
関数の後のconstは、このメンバー関数がオブジェクトの状態を変更しないことを意味します。 const Monsterでも呼び出せる関数とない関数がここで分かれる。
文字列const std::string&として返すと、文字列のコピーを避けることができます。 ただし、返された参照よりも元のオブジェクトが最初に破壊されると危険になるということは覚えておくべきです。
ポインタ
ポインタはオブジェクトのアドレスを格納します。
Monster monster;
Monster* target = &monster;
if (target != nullptr)
{
std::cout << target->GetHealth() << '\n';
}
一般的なオブジェクトは.でアクセスしてポインタが指すオブジェクトは、->に近づく。 ポインタは何も指さないかもしれないのでnullptr検査が必要です。
ここで重要なのは、ポインタがオブジェクトを指しても必ずしもそのオブジェクトを所有するわけではないということです。 誰がオブジェクトを破壊するのか決められていない生ポインタは、コードが大きくなるほど危険になります。
Monster* target = nullptr;
{
Monster monster;
target = &monster;
}
//targetはすでに破壊されたモンスターのアドレスを持っています。
このようなポインタをダングリングポインタと呼ぶ。 アドレス自体は残っていても、そのアドレスのオブジェクトはすでに寿命が終わっている。
参照は、必ず有効なオブジェクトを指す必要がある状況に使用することができ、 ポインタは、対象がない場合や他の対象を指すことができる状況にふさわしい。
そして、ポインタがオブジェクトを所有する必要がある場合は、raw pointerよりもスマートポインタを最初に考える方が良いです。