4

学習中にstd::move、奇妙な問題を見つけました。

完全なプログラムに何もしないデストラクタだけを追加すると、コンパイル エラーが発生します。

#include <iostream>
using namespace std;

class M {
public:
  int database = 0;

  M &operator=(M &&other) {
    this->database = other.database;
    other.database = 0;
    return *this;
  }

  M(M &&other) { *this = std::move(other); }

  M(M &m) = default;
  M() = default;
  ~M() { /* free db */ }
};

class B {
public:
  M shouldMove;

  //~B(){}   //<---  ## Adding this line will cause compile error. ##
};

int main() {
  B b;
  B b2 = std::move(b); //## error at this line if the above line is added
  return 0;
}

ライブコード: https://ideone.com/UTR9ob

エラーは invalid initialization of non-const reference of type 'B&' from an rvalue of type 'std::remove_reference<B&>::type {aka B}'です。

質問:

  • (1) それを強制する C++ 構文のルールはどれですか? 言い換えれば、エラーは何を意味するのでしょうか?
  • (2) ほとんど何もしない (例: デバッグ ログを出力するだけ) デストラクタを に追加したい場合、代わりに 5 つのルールBに従う必要がありますか? いいえの場合、コンパイルするにはどうすればよいですか? という理由だけで 5 のルールに従うことは、私の意見ではあまりにも退屈で汚いことです。

ゼロのルールは良い習慣 だと思います。

しかし、この例からすると、違反するとコンパイルエラーになるというのは難しいルールのように思えます。

4

1 に答える 1

6

暗黙的に宣言された移動コンストラクターは、クラスにユーザー宣言されたデストラクターがない場合にのみ存在します。したがって、2. の答えは YES です。

1. に対する答えは、これは厳格なルールであり、標準の 12.8 パラグラフ 9 にあるということです。

クラス X の定義でムーブ コンストラクターが明示的に宣言されていない場合、1 つが暗黙的にデフォルトとして宣言されます。

  • X にはユーザー宣言のコピー コンストラクターがありません。
  • X には、ユーザー宣言のコピー代入演算子がありません。
  • X には、ユーザー宣言の移動代入演算子がありません。
  • X にはユーザー宣言のデストラクタがなく、
  • 移動コンストラクターは、暗黙的に削除済みとして定義されません。

[ 注: ムーブ コンストラクターが暗黙的に宣言されていないか、明示的に提供されていない場合、そうでなければムーブ コンストラクターを呼び出す式は、代わりにコピー コンストラクターを呼び出すことができます。— エンドノート]

これを実行する最善の方法は、スマート ポインターのようなものを使用することです。つまり、5 つの特別なメンバーすべて (およびそれ以外はほとんど) を定義する基本クラスまたはメンバーを使用して、その必要がないようにします。この場合、 と同等の整数ハンドルが適切に機能するstd::unique_pointerはずです。ただし、データベースは、ファイルと同様に、閉じるときにエラーが発生する可能性があるため、スローしない標準のデストラクタ セマンティクスがすべてのケースに対応しているわけではないことに注意してください。

于 2016-12-06T06:49:29.093 に答える