コンテンツにスキップ

5. 配列、ポインター、右辺値参照

型推論

参照型の推論をする場合、auto& を使うことができます。 この場合は、参照型であることは絶対です。 よって、直値などを代入するとエラーになります。

auto& x = 0; // これはエラー

実は、decltype(auto) というものもあります。 これを使うと、初期化子の型全体を推論できます。 参照を返す関数は参照型として推論されますし、値を返す関数は値型として推論されます。

int& id(int& i) {
    return i;
}
int main() {
    decltype(auto) x = 0; // これは int 型
    decltype(auto) y = x; // これも int 型
    decltype(auto) z = id(x); // これは int& 型
    decltype(auto) _ = (x);   // これも int& 型
}

ムーブセマンティクスと左辺値参照/右辺値参照

C++11 からはムーブセマンティクスが導入されました。 ムーブセマンティクスは、オブジェクトの所有権を移動することを可能にします。 そしてムーブセマンティクスは、オブジェクトのコピーを避けることができるため、パフォーマンスを向上させることができます。

ムーブセマンティクスを導入するにあたって、右辺値であることを示すために右辺値参照が導入されました。 右辺値参照は、&& で表されます。 右辺値参照は、右辺値を参照することができます。

誤解を恐れずに言えば、右辺値とは名前をもたない一時的なオブジェクトです。 また、左辺値とは明示的に実態のある名前付きオブジェクトです。

右辺値に名前がないということは、右辺値はどこからも参照できないということです。 よって、右辺値が存在するメモリ領域は、再利用しても問題ありません。

まとめると次のようになります:

  • 左辺値は名前を持つオブジェクトである
  • 右辺値は一時的なオブジェクトである
  • 左辺値参照 (&) は左辺値のみを参照することができる
  • 右辺値参照 (&&) は右辺値のみを参照することができる

ムーブコンストラクタとムーブ代入演算子

#include <vector>
#include <utility>

int main() {
    std::vector v1 = {1, 2, 3};
    std::vector v2 = v1; // これはコピー
    std::vector v3 = std::move(v1); // これはムーブ
}

これがどういうことかというと、std::move はオブジェクトを右辺値参照型に変換する関数です。 std::move を使うことで、オブジェクトの所有権を移動することができるわけではありません。 ムーブコンストラクタやムーブ代入演算子が、オブジェクトの所有権を移動するために使用されます。 右辺値参照型を受け取るコンストラクタや代入演算子は、ムーブコンストラクタやムーブ代入演算子と呼ばれます。

#include <iostream>
#include <utility>

class MyClass {
    std::array<int, 100> data;
public:
    MyClass() = default;
    MyClass(MyClass&& other) = default; // ムーブコンストラクタ
    MyClass& operator=(MyClass&& other) = default; // ムーブ代入演算子
    ~MyClass() = default;
};

これらが右辺値参照型のための特別な処理がされることで、オブジェクトの所有権を移動することができます。 つまり辺値参照型とは、この変数はもう使わないよ、ということを示すためのものです。

理解度チェック

  1. TODO

  2. TODO

  3. TODO