名前空間
変種
操作

ムーブコンストラクタ

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-name (parameter-list ); (1)
class-name (parameter-list ) function-body (2)
class-name (single-parameter-list ) = default; (3)
class-name (parameter-list ) = delete; (4)
class-name ::class-name (parameter-list ) function-body (5)
class-name ::class-name (single-parameter-list ) = default; (6)
class-name - ムーブコンストラクタが宣言されているクラス
parameter-list - 以下の条件をすべて満たす空でないパラメータリスト
  • クラス型をTとした場合、最初のパラメータの型が T&&const T&&volatile T&&、または const volatile T&& であり、かつ
  • 他のパラメータがないか、他のすべてのパラメータがデフォルト引数を持つこと
single-parameter-list - 型が T&&const T&&volatile T&&、または const volatile T&& であり、デフォルト引数を持たない1つのパラメータのみのパラメータリスト
関数本体 - ムーブコンストラクタの関数本体

[編集] 解説

1) クラス定義内でのムーブコンストラクタの宣言。
2-4) クラス定義内でのムーブコンストラクタの定義。
3) ムーブコンストラクタが明示的にデフォルト化されている。
4) ムーブコンストラクタが削除されている。
5,6) クラス定義外でのムーブコンストラクタの定義(クラスには宣言(1)が含まれている必要がある)。
6) ムーブコンストラクタが明示的にデフォルト化されている。
struct X
{
    X(X&& other); // move constructor
//  X(X other);   // Error: incorrect parameter type
};
 
union Y
{
    Y(Y&& other, int num = 1); // move constructor with multiple parameters
//  Y(Y&& other, int num);     // Error: `num` has no default argument
};

ムーブコンストラクタは通常、オブジェクトがrvalue (xvalueまたはprvalue) (C++17まで)xvalue(C++17以降) から同じ型で初期化される場合(直接初期化またはコピー初期化によって)、次の場合に呼び出されます。

  • 初期化: T a = std::move(b); または T a(std::move(b));(ここで b は型 T);
  • 関数引数渡し: f(std::move(a));(ここで a は型 Tfvoid f(T t));
  • 関数からの戻り値: return a;T f()のような関数内で、ここで a はムーブコンストラクタを持つ型 T).

初期化子がprvalueの場合、ムーブコンストラクタの呼び出しはしばしば最適化されます(C++17まで)行われません(C++17以降)。詳細はコピー省略を参照してください。

ムーブコンストラクタは通常、引数が保持するリソース(動的に割り当てられたオブジェクトへのポインタ、ファイルディスクリプタ、TCPソケット、スレッドハンドルなど)をコピーするのではなく転送し、引数を有効だが不定な状態のままにします。ムーブコンストラクタは引数の寿命を変更しないため、通常、デストラクタは後で引数に対して呼び出されます。例えば、std::stringstd::vectorからのムーブは、引数を空のままにする可能性があります。一部の型、例えばstd::unique_ptrの場合、ムーブされた後の状態は完全に指定されます。

[編集] 暗黙的に宣言されるムーブコンストラクタ

クラス型に対してユーザー定義のムーブコンストラクタが提供されておらず、かつ以下の条件がすべて真である場合

このとき、コンパイラは、explicitでない inline public メンバとして、シグネチャ T::T(T&&) を持つムーブコンストラクタを宣言します。

クラスは複数のムーブコンストラクタを持つことができます。例えば、T::T(const T&&)T::T(T&&) の両方です。ユーザー定義のムーブコンストラクタが存在する場合でも、ユーザーはキーワード default を使って暗黙的に宣言されるムーブコンストラクタの生成を強制することができます。

暗黙的に宣言された(または最初の宣言でデフォルト化された)ムーブコンストラクタは、動的例外指定(C++17まで)noexcept指定(C++17以降) で記述されているような例外指定を持ちます。

[編集] 暗黙的に定義されるムーブコンストラクタ

暗黙的に宣言されたムーブコンストラクタが削除されておらず、かつトリビアルでない場合、ODR使用されるか、定数評価に必要な場合、コンパイラによって定義されます(つまり、関数本体が生成され、コンパイルされます)。共用体型の場合、暗黙的に定義されたムーブコンストラクタはオブジェクト表現を(std::memmoveのように)コピーします。非共用体クラス型の場合、ムーブコンストラクタは、オブジェクトの直接基底サブオブジェクトとメンバサブオブジェクトの完全なメンバごとのムーブを、初期化順に、xvalue引数を使用した直接初期化によって実行します。参照型である各非静的データメンバについて、ムーブコンストラクタは、ソース参照がバインドされているのと同じオブジェクトまたは関数に参照をバインドします。

これがconstexprコンストラクタ(C++23まで)constexpr関数(C++23以降)の要件を満たす場合、生成されたムーブコンストラクタはconstexprになります。

[編集] 削除されたムーブコンストラクタ

クラス T の暗黙的に宣言された、または明示的にデフォルト化されたムーブコンストラクタは、T がクラス型 M潜在的に構築されるサブオブジェクト(またはその多次元配列)を以下の条件を満たす場合に削除として定義されます。

  • M のデストラクタが削除されているか、コピーコンストラクタからアクセスできない場合、または
  • M のムーブコンストラクタを見つけるために適用されたオーバーロード解決が
  • 使用可能な候補をもたらさない場合、または
  • サブオブジェクトがバリアントメンバである場合、非トリビアルな関数を選択する場合。

このようなコンストラクタはオーバーロード解決によって無視されます(そうでなければ、rvalueからのコピー初期化を妨げることになります)。

[編集] トリビアルなムーブコンストラクタ

クラス T のムーブコンストラクタは、以下のすべてが真である場合にトリビアルです。

  • ユーザーによって提供されていない(つまり、暗黙的に定義されているか、デフォルト化されている);
  • T に仮想メンバ関数がない;
  • T に仮想基底クラスがない;
  • T のすべての直接基底に対して選択されたムーブコンストラクタがトリビアルである;
  • T のすべての非静的クラス型(またはクラス型の配列)メンバに対して選択されたムーブコンストラクタがトリビアルである。

トリビアルなムーブコンストラクタは、トリビアルなコピーコンストラクタと同じ動作を実行するコンストラクタであり、つまりstd::memmoveによってかのようにオブジェクト表現のコピーを作成します。C言語と互換性のあるすべてのデータ型はトリビアルに移動可能です。

[編集] 適格なムーブコンストラクタ

ムーブコンストラクタは、削除されていない場合に適格です。

(C++20まで)

ムーブコンストラクタは、以下のすべての条件が満たされている場合に適格です。

  • 削除されていない。
  • その関連する制約(もしあれば)が満たされている。
  • その関連する制約が満たされているムーブコンストラクタで、より制約されているものがない。
(C++20以降)

適格なムーブコンストラクタのトリビアル性は、クラスが暗黙的な寿命を持つ型であるか、トリビアルにコピー可能な型であるかを決定します。

[編集] 備考

強力な例外保証を可能にするため、ユーザー定義のムーブコンストラクタは例外を投げないようにすべきです。例えば、std::vectorは、要素を再配置する必要がある場合にムーブとコピーのどちらを選択するかをstd::move_if_noexceptに依存しています。

コピーコンストラクタとムーブコンストラクタの両方が提供されており、他のコンストラクタが有効でない場合、引数が同じ型のrvaluestd::moveの結果のようなxvalueまたは名前のない一時オブジェクトのようなprvalue(C++17まで))であればムーブコンストラクタが選択され、引数がlvalue(名前付きオブジェクトまたはlvalue参照を返す関数/演算子)であればコピーコンストラクタが選択されます。コピーコンストラクタのみが提供されている場合、すべての引数カテゴリがそれを選択します(rvalueはconst参照にバインドできるため、const参照を受け取る限りにおいて)。これにより、ムーブが利用できない場合のフォールバックとしてコピーが機能します。

[編集]

#include <iomanip>
#include <iostream>
#include <string>
#include <utility>
 
struct A
{
    std::string s;
    int k;
 
    A() : s("test"), k(-1) {}
    A(const A& o) : s(o.s), k(o.k) { std::cout << "move failed!\n"; }
    A(A&& o) noexcept :
        s(std::move(o.s)),       // explicit move of a member of class type
        k(std::exchange(o.k, 0)) // explicit move of a member of non-class type
    {}
};
 
A f(A a)
{
    return a;
}
 
struct B : A
{
    std::string s2;
    int n;
    // implicit move constructor B::(B&&)
    // calls A's move constructor
    // calls s2's move constructor
    // and makes a bitwise copy of n
};
 
struct C : B
{
    ~C() {} // destructor prevents implicit move constructor C::(C&&)
};
 
struct D : B
{
    D() {}
    ~D() {}           // destructor would prevent implicit move constructor D::(D&&)
    D(D&&) = default; // forces a move constructor anyway
};
 
int main()
{
    std::cout << "Trying to move A\n";
    A a1 = f(A()); // return by value move-constructs the target
                   // from the function parameter
 
    std::cout << "Before move, a1.s = " << std::quoted(a1.s)
        << " a1.k = " << a1.k << '\n';
 
    A a2 = std::move(a1); // move-constructs from xvalue
    std::cout << "After move, a1.s = " << std::quoted(a1.s)
        << " a1.k = " << a1.k << '\n';
 
 
    std::cout << "\nTrying to move B\n";
    B b1;
 
    std::cout << "Before move, b1.s = " << std::quoted(b1.s) << "\n";
 
    B b2 = std::move(b1); // calls implicit move constructor
    std::cout << "After move, b1.s = " << std::quoted(b1.s) << "\n";
 
 
    std::cout << "\nTrying to move C\n";
    C c1;
    C c2 = std::move(c1); // calls copy constructor
 
    std::cout << "\nTrying to move D\n";
    D d1;
    D d2 = std::move(d1);
}

出力

Trying to move A
Before move, a1.s = "test" a1.k = -1
After move, a1.s = "" a1.k = 0
 
Trying to move B
Before move, b1.s = "test"
After move, b1.s = ""
 
Trying to move C
move failed!
 
Trying to move D

[編集] 欠陥報告

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

DR 適用対象 公開された動作 正しい動作
CWG 1353 C++11 デフォルト化されたムーブコンストラクタが
削除として定義される条件が多次元配列型を考慮していなかった
これらの型を考慮する
CWG 1402 C++11 非トリビアルなコピーコンストラクタを呼び出す
デフォルト化されたムーブコンストラクタが削除として定義されていた。
削除されたデフォルト化されたムーブコンストラクタが
オーバーロード解決にまだ参加していた。
そのようなコピーを呼び出し可能にしていた。
オーバーロード解決で無視されるようにした。
オーバーロード解決で無視されるようにした
CWG 1491 C++11 rvalue参照型の非静的データメンバを持つクラスの
デフォルト化されたムーブコンストラクタが削除として定義されていた。
この場合は削除されない。
CWG 2094 C++11 volatileサブオブジェクトがデフォルト化されたムーブコンストラクタを
非トリビアルにしていた(CWG issue 496)。
トリビアル性は影響を受けない。
CWG 2595 C++20 より制約されているがその関連する制約を満たさない別のムーブコンストラクタが
存在する場合、ムーブコンストラクタは適格ではなかった。
だがその関連する制約を満たさない
この場合でも適格になりうる。

[編集] 関連項目

English 日本語 中文(简体) 中文(繁體)