web-dev-qa-db-ja.com

クラスのメソッドに対する `= delete`の正しい使用

次のスニペットは、クラスに対して生成されたすべてのメソッドとコンストラクターの定義を解除するのに正しいですか?

_struct Picture {

  // 'explicit': no accidental cast from string to Picture
  explicit Picture(const string &filename) { /* load image from file */ }

  // no accidental construction, i.e. temporaries and the like
  Picture() = delete;

  // no copy
  Picture(const Picture&) = delete;

  // no assign
  Picture& operator=(const Picture&) = delete;

  // no move
  Picture(Picture&&) = delete;

  // no move-assign
  Picture& operator=(Picture&&) = delete; // return type correct?
};
_

これにより、デフォルトのコンパイラ実装がすべて削除され、デストラクタだけが残ります。それがないと、クラスは(ほとんど)使用できなくなると思いますが、削除することもできますよね?

ムーブ代入operator=(Picture&&)の戻り値の型_Picture&_は正しいですか?戻り値の型に_Picture&&_を記述した場合、違いはありますか?

31
towi

Xeoの答えに加えて:

はい、すべてが正しいです。必要に応じて、削除されたすべてのメンバーを削除できますが、削除されたコピーコンストラクターと削除されたコピーの割り当ては同じ効果があります。

struct Picture {  // Also ok

  // 'explicit': no accidental cast from string to Picture
  explicit Picture(const string &filename) { /* load image from file */ }

  // no copy
  Picture(const Picture&) = delete;

  // no assign
  Picture& operator=(const Picture&) = delete;
};

コピーコンストラクターの明示的な宣言は、デフォルトコンストラクター、ムーブコンストラクター、およびムーブ代入メンバーの暗黙的な生成を禁止します。これらのメンバーを明示的に削除するのは好みの問題です。おそらくそれを良いドキュメントと見なす人もいるでしょう。他の人はそれを過度に冗長であると見なすかもしれません。

27
Howard Hinnant

私には問題ないようです。 _operator=_ 必須の戻り値は、オブジェクトが右辺値参照から構築されている場合でも、通常の参照です。これは、左辺値(_*this_)を右辺値にコンパイルするだけでは不十分だからです。
そして、非const Picture& operator=(Picture&&)ごとにその右辺値参照を取得する必要があります。一定のオブジェクトからどのように移動しますか? ;)

3
Xeo