名前空間
変種
操作

インクリメント/デクリメント演算子

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

インクリメント/デクリメント演算子は、オブジェクトの値をインクリメントまたはデクリメントします。

演算子名 構文 オーバーロード可能 プロトタイプの例 (class T の場合)
クラス定義内 クラス定義外
前置インクリメント ++a はい T& T::operator++(); T& operator++(T& a);
前置デクリメント --a はい T& T::operator--(); T& operator--(T& a);
後置インクリメント a++ はい T T::operator++(int); T operator++(T& a, int);
後置デクリメント a-- はい T T::operator--(int); T operator--(T& a, int);
注釈
  • 組み込み演算子の前置バージョンは*参照*を返し、後置バージョンは*値*を返し、典型的なユーザー定義オーバーロードも同様のパターンに従うため、ユーザー定義演算子も組み込み演算子と同じように使用できます。ただし、ユーザー定義演算子のオーバーロードでは、任意の型を戻り値型として使用できます(voidを含む)。
  • intパラメータは、演算子の前置バージョンと後置バージョンを区別するために使用されるダミーパラメータです。ユーザー定義の後置演算子が呼び出されるとき、そのパラメータに渡される値は常にゼロですが、関数呼び出し表記(例: a.operator++(2) または operator++(a, 2))を使用して演算子を呼び出すことで変更される可能性があります。

目次

[編集] 前置演算子

前置インクリメントおよびデクリメント式は次の形式を持ちます。

++
--
1) 前置インクリメント (pre-increment)
2) 前置デクリメント (pre-decrement)

[編集] 組み込み前置演算子

1)++xx += 1 と同等ですが、以下の例外があります。
  • の型が (おそらく揮発性修飾された) bool の場合、true に設定されます。このようなインクリメントは非推奨です。
(C++17まで)
  • の型が (おそらく cv 修飾された) bool の場合、プログラムは ill-formed です。
(C++17以降)
  • の型が揮発性修飾されている場合、インクリメントは非推奨です。
(C++20以降)
2)--xx -= 1 と同等ですが、以下の例外があります。
  • の型が (おそらく cv 修飾された) bool の場合、プログラムは ill-formed です。
  • の型が揮発性修飾されている場合、デクリメントは非推奨です。
(C++20以降)

[編集] オーバーロード

ユーザー定義演算子に対するオーバーロード解決では、bool 以外のすべての任意に volatile 修飾された算術型 A、およびすべての任意に volatile 修飾された任意に cv 修飾されたオブジェクト型へのポインタ P について、以下の関数シグネチャがオーバーロード解決に参加します。

A& operator++(A&)
bool& operator++(bool&)
(非推奨)(C++17まで)
P& operator++(P&)
A& operator--(A&)
P& operator--(P&)

[編集] 後置演算子

後置インクリメントおよびデクリメント式は次の形式を持ちます。

++
--
1) 後置インクリメント (post-increment)
2) 後置デクリメント (post-decrement)

[編集] 組み込み後置演算子

後置インクリメントまたはデクリメントの結果は、に (変更前の)lvalue-to-rvalue変換を適用して得られる値です。結果の型は、の型のcv非修飾バージョンです。

が (おそらく cv 修飾された) bool 以外の算術型または完全なオブジェクト型へのポインタの変更可能な lvalue ではない場合(C++17以降)、プログラムは ill-formed です。

の型が揮発性修飾されている場合、インクリメントまたはデクリメントは非推奨です。

(C++20以降)
1) の値は、それが前置 ++ 演算子のオペランドであるかのように変更されます。
2) の値は、それが前置 -- 演算子のオペランドであるかのように変更されます。

後置インクリメントまたはデクリメントの値計算は、の変更より前にシーケンスされます。不確定な順序の関数呼び出しに関して、後置インクリメントまたはデクリメントの操作は単一の評価です。

[編集] オーバーロード

ユーザー定義演算子に対するオーバーロード解決では、bool 以外のすべての任意に volatile 修飾された算術型 A、およびすべての任意に volatile 修飾された任意に cv 修飾されたオブジェクト型へのポインタ P について、以下の関数シグネチャがオーバーロード解決に参加します。

A operator++(A&, int)
bool operator++(bool&, int)
(非推奨)(C++17まで)
P operator++(P&, int)
A operator--(A&, int)
P operator--(P&, int)

[編集]

#include <iostream>
 
int main()
{
    int n1 = 1;
    int n2 = ++n1;
    int n3 = ++ ++n1;
    int n4 = n1++;
//  int n5 = n1++ ++;   // error
//  int n6 = n1 + ++n1; // undefined behavior
    std::cout << "n1 = " << n1 << '\n'
              << "n2 = " << n2 << '\n'
              << "n3 = " << n3 << '\n'
              << "n4 = " << n4 << '\n';
}

出力

n1 = 5
n2 = 2
n3 = 4
n4 = 4

[編集] 注釈

副作用が伴うため、組み込みのインクリメントおよびデクリメント演算子は、シーケンス規則の違反による未定義動作を避けるために注意して使用する必要があります。

後置インクリメントおよび後置デクリメントではオブジェクトの一時的なコピーが構築されるため、戻り値が使用されないコンテキストでは、前置インクリメントまたは前置デクリメント演算子の方が通常は効率的です。

[編集] 標準ライブラリ

インクリメントおよびデクリメント演算子は、多くの標準ライブラリ型でオーバーロードされています。特に、すべてのLegacyIteratoroperator++ をオーバーロードし、すべてのLegacyBidirectionalIteratoroperator-- をオーバーロードします。たとえそれらの演算子が特定のイテレータにとって何もしない場合でもです。

算術型に対するオーバーロード
アトミック値を1増減させる
(std::atomic<T> のパブリックメンバ関数) [編集]
ティック数を増減する
(std::chrono::duration<Rep,Period> のパブリックメンバ関数) [編集]
イテレータ型に対するオーバーロード
イテレータを進める
(std::raw_storage_iterator<OutputIt,T> のパブリックメンバ関数) [編集]
reverse_iterator を進めるかデクリメントする
(std::reverse_iterator<Iter> のパブリックメンバ関数) [編集]
move_iteratorを進める、または減らす
(std::move_iterator<Iter> のパブリックメンバ関数) [編集]
何も行わない
(std::front_insert_iterator<Container> のパブリックメンバ関数) [編集]
何も行わない
(std::back_insert_iterator<Container> のパブリックメンバ関数) [編集]
何も行わない
(std::insert_iterator<Container> のパブリックメンバ関数) [編集]
イテレータを進める
(std::istream_iterator<T,CharT,Traits,Distance> のパブリックメンバ関数) [編集]
何も行わない
(std::ostream_iterator<T,CharT,Traits> のパブリックメンバ関数) [編集]
イテレータを進める
(std::istreambuf_iterator<CharT,Traits> のパブリックメンバ関数) [編集]
何も行わない
(std::ostreambuf_iterator<CharT,Traits> のパブリックメンバ関数) [編集]
イテレータを次のマッチに進める
(std::regex_iterator<BidirIt,CharT,Traits> のパブリックメンバ関数) [編集]
イテレータを次のサブマッチに進める
(std::regex_token_iterator<BidirIt,CharT,Traits> のパブリックメンバ関数) [編集]

[編集] 欠陥報告

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
CWG 2855 C++98 組み込みの前置インクリメントおよび
前置デクリメントには通常の算術変換が適用されるが、後置の対応物には適用されなかった[1]
も適用される
CWG 2901 C++98 組み込みの後置インクリメントおよび後置デクリメントには
lvalue-to-rvalue 変換が適用されなかった
適用済み
  1. 前置 ++xx += 1 と同等であり、後者は通常の算術変換 (すなわち、decltype(x)int の間の共通の型を生成する) が適用可能です。しかし、後置 x++ の効果は単に「x に1を加える」ことであり、二項演算子が存在しないため、通常の算術変換は行われません。

[編集] 関連項目

演算子の優先順位

演算子のオーバーロード

共通の演算子
代入 インクリメント
デクリメント
算術 論理 比較 メンバ
アクセス
その他

a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b

++a
--a
a++
a--

+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

!a
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[...]
*a
&a
a->b
a.b
a->*b
a.*b

関数呼び出し

a(...)
コンマ

a, b
conditional

a ? b : c
特殊な演算子

static_castは、ある型を関連する別の型に変換する
dynamic_castは、継承階層内で変換する
const_castは、cv修飾子を追加または削除する
reinterpret_castは、型を関連のない型に変換する
C形式のキャストは、static_castconst_castreinterpret_castの組み合わせによって、ある型を別の型に変換する
newは、動的ストレージ期間を持つオブジェクトを作成する
deleteは、new式によって以前に作成されたオブジェクトを破棄し、取得したメモリ領域を解放する
sizeofは、型のサイズを問い合わせる
sizeof...は、パラメータパックのサイズを問い合わせる (C++11以降)
typeidは、型の型情報を問い合わせる
noexceptは、式が例外を投げる可能性があるかどうかをチェックする (C++11以降)
alignofは、型のアライメント要件を問い合わせる (C++11以降)

C ドキュメント (インクリメント/デクリメント演算子)
English 日本語 中文(简体) 中文(繁體)