質問するログイン新規登録
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

2回答

101閲覧

"C++" 左辺値と右辺値の違いが判りません。前置形式は左辺に置けるのに後置形式は左辺に置けないのですか

0fg3873t38k3z3e

総合スコア1

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2025/09/14 08:19

0

0

//前置形式++xは《左辺値式》で後置形式x++は《右辺値式》であることを確認

#include <iostream>

using namespace std;

int main()
{
int x=0;
++x=5; //OK:前置形式は左辺に置ける
cout<<"xの値は"<<x<<"です。\n"

x++=10; //エラー:後置形式は左辺に置けない
cout<<"xの値は"<<x<<"です。\n"
}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

Google Gemini 2.5 Pro による回答


C++において後置形式は左辺に置けないことに関する仕様の説明はどこに書かれていますか?

C++において後置形式 (i++) が左辺に置けないことに関する仕様は、C++の国際規格(ISO/IEC 14882)の中で、主に以下の2つのルールの組み合わせによって定義されています。

  1. 後置インクリメント演算子の結果は「右辺値」である。
  2. 代入演算子 (=) の左辺には「左辺値」が必要である。

この仕様が記載されている具体的な箇所は、規格書の 「Expressions(式)」 のセクションです。


## 仕様の詳細

1. 後置インクリメントの結果は prvalue (右辺値)

C++規格の [expr.post.incr] (Postfix increment and decrement) という項目に、後置インクリメント (++) およびデクリメント (--) 演算子に関する規定があります。

ここには、以下のような内容が記載されています(C++17の草案 N4659 8.2.6 より引用・意訳)。

The value of a postfix ++ expression is the value of its operand. [...] The result is a prvalue.
(後置 ++ 式の値は、そのオペランドの値である。[...] その結果は prvalue である。)

prvalue(pure rvalue、純粋右辺値)とは、リテラル (10など) や一時的な計算結果のように、特定のメモリ位置を持たない「その場限りの値」を指します。これが、一般に言われる右辺値 (rvalue) の一種です。

つまり、i++ という式は、「iがインクリメントされる前の値」を持つ一時的な値を生成し、それが式全体の結果となります。


2. 代入演算子は左辺に lvalue を要求する

次に、代入演算子 (=) の仕様です。これは [expr.ass] (Assignment and compound assignment operators) という項目で定義されています。

ここには、以下のような制約が記載されています(8.5.18 より引用・意訳)。

The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand.
(代入演算子 (=) と複合代入演算子はすべて右から左に結合する。すべて、その左オペランドとして変更可能な左辺値 (modifiable lvalue) を要求する。)

左辺値 (lvalue) とは、prvalue とは対照的に、特定のメモリ位置を持ち、そのアドレスを取得できるようなオブジェクトを指します。変数名などがその代表例です。代入とは、特定のメモリ位置の値を書き換える操作なので、左辺にはその「位置」が特定できるもの、つまり左辺値が必要なのです。


## 結論

以上の2つのルールを組み合わせると、後置形式がなぜ左辺に置けないかが明確になります。

  • i++ という式が返す結果は、規格によって prvalue (右辺値) と定められている。
  • = 演算子の左辺には、規格によって lvalue (左辺値) が必要と定められている。

したがって、(i++) = 10; というコードは、右辺値に対して代入を行おうとしているため、規格違反となりコンパイラによってエラーとして弾かれます。

ちなみに、前置形式 (++i) は、同じく規格で結果が lvalue であると定められているため、(++i) = 10; のようなコードは文法的に正しいものとなります。


C++において、前置形式は左辺に置けるのに、なぜ後置形式は左辺に置けないのですか?

C++で前置形式が左辺に置けて、後置形式が置けないのは、それぞれの演算子が返す「値の性質」が根本的に異なるためです。

端的に言えば、前置形式は「オブジェクトそのもの(左辺値)」を返し、後置形式は「変更前の値のコピー(右辺値)」を返すからです。代入式の左辺には、実体を持つオブジェクト、つまり左辺値しか置くことができません。


## 前置形式 (++i--i) の仕組み

前置インクリメント(またはデクリメント)は、以下の手順で動作します。

  1. 変数の値を先にインクリメント(またはデクリメント)します。
  2. 値が変更された変数そのものを返します。

返されるのは、メモリ上に実体を持つ「変数そのもの」です。このような、アドレスを特定でき、代入式の左側に置けるものを左辺値 (lvalue) と呼びます。

そのため、以下のような一見奇妙なコードも文法的には正しくなります。

cpp

1int i = 5; 2(++i) = 10; // まず i が 6 になり、その i に 10 が代入される 3// この行の後、i の値は 10 になる

このコードは i を6にしてから、その i に10を代入しているため、最終的に i は10になります。実用的な意味はほとんどありませんが、前置形式が左辺値を返す良い例です。


## 後置形式 (i++i--) の仕組み

一方、後置インクリメント(またはデクリメント)は、少し複雑な手順で動作します。

  1. 変数の現在の値を、内部的な一時領域にコピーして保存します。
  2. 元の変数の値をインクリメント(またはデクリメント)します。
  3. 保存しておいた変更前の値のコピーを返します。

ここで返されるのは、元の変数とは別のメモリ領域に作成された「一時的な値」です。この様な、その場限りで消えてしまう値を右辺値 (rvalue) と呼びます。右辺値は 5true といったリテラルと同じで、メモリ上の固定された場所を持たないため、代入の対象にできません。

10 = 20; というコードが意味をなさないのと同じように、後置形式が返した一時的な値に何かを代入しようとすると、コンパイルエラーになります。

cpp

1int i = 5; 2(i++) = 10; // コンパイルエラー! 3// i++ が返すのは、iが5だった頃の「コピー(値は5)」。 4// この一時的な値「5」に10を代入しようとしているのと同じこと。

## まとめとアドバイス

形式動作返り値の性質左辺に置けるかどうか
前置 (++i)値を変更し、変更後のオブジェクトを返す左辺値 (lvalue)
後置 (i++)値のコピーを取り、値を変更し、コピーを返す右辺値 (rvalue)

この違いから、パフォーマンスに関する重要な示唆も得られます。後置形式は値のコピーを生成するためのオーバーヘッドが僅かですがあります。整数型のような基本的な型ではコンパイラが最適化してくれるため差はほとんどありませんが、イテレータのような複雑なクラスでは、このコピーコストが無視できない場合があります。

そのため、C++プログラマーの間では、特に理由がない限り、前置形式 (++i) を使うのが一般的です。特に for ループでは、後置形式を使う必要はほとんどありません。

cpp

1// 変更前の値が必要ないなら、こちらが効率的で好ましい 2for (int i = 0; i < 10; ++i) { 3 // ... 4}

※ Gemini は不正確な情報を表示することがあるため、生成された回答を再確認するようにしてください。

投稿2025/09/14 09:42

melian

総合スコア21453

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

詳細な規則は仕様を読むしかないのですが、基本的な考え方として……

たとえば

int x = 1; x = 2;

は OK でも

1 = 2;

が駄目だというのはわかりますね。

x = 2; という式における xx に格納されている 1 はどうでもよくて x という場所に意味があるからです。

場所と結びついているような式が左辺値 (lvalue) です。


もう一方の右辺値 (rvalue) とは何であるかというと一時的な値のことです。

たとえば 1+2+5 という式があったときまずは 1+2 が計算されて 3 になり、 35 が足されて 8 になります。 式全体の計算が終わったときに 3 はどこへ行ったのでしょう?

このような値は式の終わりに寿命を終えることになっており、一時的な寿命しか持ちません。 これが右辺値です。

++x では x の値を更新し式の評価結果は更新後の x そのものとなりこれは一時的な値ではなく場所と結びついた左辺値です。

x++ の場合は更新前の値がコピーされた上で x を更新します。 そして式の評価結果はコピーされた一時的な値なので右辺値です。

式の終わりに消滅するものを書き換えたところで意味がありませんし、もしそういうことをしていたなら間違ったプログラムであろうことは明らかなので代入は出来ないようになっています。


ちなみに現在の C++ では左辺値 (lvalue) と右辺値 (rvalue) だけではなく glvalue xvalue prvalue もあり、階層的な分類になっています。

投稿2025/09/14 08:49

SaitoAtsushi

総合スコア5749

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問