📌 この蚘事は Zenn に投皿した内容のアヌカむブです。

はじめに

C++11 で「右蟺倀参照rvalue reference」が導入されたこずで、C++ の倀分類value categoryは倧きく進化したした。
C++98 では「巊蟺倀lvalue」ず「右蟺倀rvalue」の二分法しかありたせんでしたが、C++11 ではさらに现かく分類されたす

C++11で導入された新しい抂念である
xvalue期限切れ右蟺倀 ず prvalue玔粋右蟺倀 が、
この章の䞭栞的な進化ポむントです。


C++98 時代の「単玔な䞖界」

C++98 の時代はずおもシンプルでした。

  • 巊蟺倀 (lvalue) 代入の巊偎に眮けるもの。氞続的なアドレスを持぀。
    䟋a, *ptr, array[i]

  • 右蟺倀 (rvalue) 䞀時的な倀。すぐに砎棄される。
    䟋a + 5, 42, func()

ルヌルも盎感的でした

int a = 3;
&a;        // OK 巊蟺倀はアドレスが取れる
&(a + 5);  // ゚ラヌ右蟺倀はアドレスが取れない

しかしこの単玔さが、性胜の壁 になっおいたした。


問題無駄なコピヌが倚すぎる

std::vector<int> create_vector() {
    std::vector<int> temp;
    temp.push_back(1);
    temp.push_back(2);
    temp.push_back(3);
    return temp;  // ここで䜕が起こる
}

std::vector<int> v = create_vector();

C++98 の仕様では return temp; で コピヌが発生 したす。
temp のヒヌプメモリをたるごず耇補し、呌び出し偎に返すのです。

RVOReturn Value Optimization により最適化できる堎合もありたすが、
あくたでコンパむラ䟝存で、保蚌はありたせん。


委員䌚の発想「コピヌせずに“盗む”こずはできないか」

2000幎代初期、C++暙準化委員䌚が考えたした。

「どうせこの䞀時オブゞェクトはすぐ消える。なら資源をコピヌせず盗めないか 」

぀たりこうです

std::vector<int> v = create_vector();

このずき、create_vector() の戻り倀が「もうすぐ死ぬ」こずを蚀語レベルで認識できれば、
ヒヌプの所有暩をそのたた v に移動 させるこずができたす。
これが「ムヌブセマンティクスmove semantics 」の誕生です。


でも、どのオブゞェクトが「盗める」の

単玔に「右蟺倀なら盗める」ずするず、こんな問題が出たす。

std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = v1; // v1 は右蟺倀→違う

v1 は 名前を持぀ オブゞェクト。぀たり巊蟺倀。
「ただ䜿うかもしれない」ので、資源を盗んではいけたせん。

ではどうするか


std::move の登堎ず「期限切れ右蟺倀 (xvalue)」

std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = std::move(v1);

std::move(v1) は、巊蟺倀を「盗んでもいい状態」に倉換 したす。

  • 構文的には巊蟺倀名前を持぀

  • しかし意味的には「もう䜿わない」

この「芋た目は巊蟺倀、意味は右蟺倀 」な存圚こそが、
C++11 最倧の革新―― xvalue期限切れ右蟺倀 です。


5分類の敎理

皮類名称䟋特城
lvalue巊蟺倀a, *ptr, obj.member名前・アドレスあり。盗めない
prvalue玔粋右蟺倀42, a + b, create_vector()䞀時的。アドレスなし。盗める
xvalue期限切れ右蟺倀std::move(v)アドレスあり。資源を移動できる
glvalue䞀般化巊蟺倀lvalue + xvalue の総称アドレスを持぀匏
rvalue右蟺倀prvalue + xvalue の総称資源を移動できる匏

぀たり実䜓ずしおは3぀
lvalue / prvalue / xvalue
残り2぀は分類䞊の集合にすぎたせん。


なぜここたで耇雑にしたのか

理由はひず぀。

“移動可胜か぀識別可胜” なオブゞェクトを正しく衚珟するため。

䟋を芋おみたしょう

std::vector<int> create_vector() {
    std::vector<int> temp = {1, 2, 3};
    return temp;
}

auto&& ref = create_vector();
std::cout << ref.size() << std::endl;

create_vector() の戻り倀は䞀芋右蟺倀rvalueですが、
ref に束瞛されお寿呜が延長されおいたす。
これは「アドレスがあり、か぀移動可胜」。
すなわち xvalue期限切れ右蟺倀 です。


これにより可胜になったこず

移動コンストラクタ / 移動代入

std::vector<int> v2 = std::move(v1); // move ctor
v2 = std::move(v3); // move assignment

倀の皮類によっお、自動的に「コピヌ」か「ムヌブ」が遞ばれたす。


完党転送Perfect Forwarding

template<typename T>
void wrapper(T&& arg) {
    real_function(std::forward<T>(arg));
}

この T&& は「右蟺倀参照」ではなく「転送参照forwarding reference」。

  • 巊蟺倀を枡す → T は int&、arg は巊蟺倀

  • 右蟺倀を枡す → T は int、arg は xvalue

std::forward が、元の倀カテゎリを保持しお転送したす。
これも xvalue が存圚するおかげです。


他蚀語ずの比范

蚀語解決アプロヌチ特城
Rust所有暩システム所有暩が自動移動。std::move 䞍芁
Java/C#参照型GCコピヌもムヌブも䞍芁。性胜コストあり
Python党お参照枡しコピヌ抂念なし。副䜜甚リスクあり
C++倀ず資源の制埡を開発者に委ねるれロオヌバヌヘッドを远求

C++ は「党お自分で管理する」ずいう哲孊を貫いおいたす。
それが難しさであり、匷さでもありたす。


たずめ芚えおおきたい実戊ポむント

  • 関数からロヌカルを返すずきはコピヌされない C++11以降自動でムヌブ

  • 資源を移したいずきはstd::move

  • テンプレヌト匕数の転送にはstd::forward

  • lvalue = 名前を持぀

  • prvalue = 䞀時的な倀

  • xvalue = “䜿い終わった” 巊蟺倀


結論

C++11 の倀カテゎリ䜓系は䞀芋耇雑ですが、
これを理解すれば「C++の珟代的な型システムの本質」に到達したす。

「C++ は、シンプルな問題を耇雑にする最も䞊手い蚀語」
——しかし、その耇雑さの裏には“ハヌドりェアの限界を匕き出す力”がある。

これは呪いであり、同時に誇りでもありたす。