ムーブに関するユーティリティ 解答ページ | Programming Place Plus Modern C++編【標準ライブラリ】 第2章

トップページModern C++編 C++編](../../index.html) – 第2章

Modern C++編は作りかけで、更新が停止しています。代わりに、C++14 をベースにして、その他の方針についても見直しを行った、新C++編を作成しています。
Modern C++編は削除される予定です。

問題①

問題① コピーやムーブに関するメンバ関数を定義したりしなかったりすることで、std::swap関数の挙動がどう変わるか確認してください。


ムーブコンストラクタ、ムーブ代入演算子が使えるのならば、これが使われます。

#include <iostream>
#include <utility>

class MyClass {
public:
    MyClass(int v) : mValue(v) {}
    MyClass(const MyClass& rhs) : mValue(rhs.mValue)
    {
        std::cout << "copy construtor" << std::endl;
    }
    MyClass(MyClass&& rhs) : mValue(rhs.mValue)
    {
        std::cout << "move construtor" << std::endl;
    }
    
    ~MyClass() = default;

    MyClass& operator=(const MyClass& rhs)
    {
        std::cout << "copy" << std::endl;
        mValue = rhs.mValue;
        return *this;
    }
    MyClass& operator=(MyClass&& rhs)
    {
        std::cout << "move" << std::endl;
        if (this != &rhs) {
            mValue = rhs.mValue;
        }
        return *this;
    }

    inline int GetValue() const
    {
        return mValue;
    }

private:
    int mValue;
};

int main()
{
    MyClass a(10);
    MyClass b(20);
    std::swap(a, b);
    std::cout << a.GetValue() << ", " << b.GetValue() << std::endl;
}

実行結果:

move construtor
move
move
20, 10

ムーブコンストラクタとムーブ代入演算子が無ければ、コピーが使われます。

#include <iostream>
#include <utility>

class MyClass {
public:
    MyClass(int v) : mValue(v) {}
    MyClass(const MyClass& rhs) : mValue(rhs.mValue)
    {
        std::cout << "copy construtor" << std::endl;
    }
    
    ~MyClass() = default;

    MyClass& operator=(const MyClass& rhs)
    {
        std::cout << "copy" << std::endl;
        mValue = rhs.mValue;
        return *this;
    }

    inline int GetValue() const
    {
        return mValue;
    }

private:
    int mValue;
};

int main()
{
    MyClass a(10);
    MyClass b(20);
    std::swap(a, b);
    std::cout << a.GetValue() << ", " << b.GetValue() << std::endl;
}

実行結果:

copy construtor
copy
copy
20, 10

ここで、ムーブコンストラクタとムーブ代入演算子を「= delete」で削除した場合は、コンパイルエラーになります。基本的にムーブを使用としますから、ムーブコンストラクタやムーブ代入演算子を呼び出そうとしますが、これが削除されていたら、その時点でコンパイルエラーになります(【言語解説】第10章)。

#include <iostream>
#include <utility>

class MyClass {
public:
    MyClass(int v) : mValue(v) {}
    MyClass(const MyClass& rhs) : mValue(rhs.mValue)
    {
        std::cout << "copy construtor" << std::endl;
    }
    MyClass(MyClass&& rhs) = delete;
    
    ~MyClass() = default;

    MyClass& operator=(const MyClass& rhs)
    {
        std::cout << "copy" << std::endl;
        mValue = rhs.mValue;
        return *this;
    }
    MyClass& operator=(MyClass&& rhs) = delete;

    inline int GetValue() const
    {
        return mValue;
    }

private:
    int mValue;
};

int main()
{
    MyClass a(10);
    MyClass b(20);
    std::swap(a, b);
    std::cout << a.GetValue() << ", " << b.GetValue() << std::endl;
}

問題②

問題② int型はムーブによる生成や、ムーブ代入ができますか? また、const int型ならどうでしょうか?


int型のような標準の型はムーブできますが、const が付いていたら変更不能なため、ムーブ代入の代入先になることができません。このことは実際に試してみれば一目瞭然です。

#include <iostream>
#include <utility>

int main()
{
    int a = 10;
    int b = std::move(a);  // OK
    a = std::move(b);      // OK

    const int ca = 10;
    const int cb = std::move(ca);  // OK
    ca = std::move(cb);            // コンパイルエラー。const変数は書き換えられない
}

std::is_move_constructible と std::is_move_assignable を使って調べてみましょう。

#include <iostream>
#include <type_traits>

int main()
{
    std::cout << std::is_move_constructible<int>::value << " "
              << std::is_move_assignable<int>::value << std::endl;
    std::cout << std::is_move_constructible<const int>::value << " "
              << std::is_move_assignable<const int>::value << std::endl;
}

実行結果:

1 1
1 0

予定どおりの結果が得られました。



参考リンク


更新履歴

’2017/8/26 新規作成。



第2章のメインページへ

Modern C++編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る