9

これ:

void foo(int &&r) {
  std::cout << r << std::endl;
}

int main() {
  int i = 2;
  foo(std::move(i));
  i = 3; //no warning. any way to get some warnings here?
  return 0;
}

変数を移動した後に誤って変数を使用した場合、コンパイラにエラー (または警告) を与えるように指示する方法はありませんか? これはとても便利だと思います。多くの場合、変数をそのように別の場所に移動していることに気付きますが、後で使用しないように手動で非常に注意する必要があります。これでまだ問題は発生していませんが、今後のことは誰にもわかりません...安全に気をつけてください!

たぶん、このようなことを行うために存在するプリプロセッサのトリック(またはかなり広く利用可能なコンパイラ拡張機能)がいくつかありますか?


より現実的な例:

struct HugeStorage {
  std::vector<double> m_vec;
  HugeStorage(std::vector<double> vec) : m_vec(std::move(vec)) { }
};

struct SmallStorage {
  std::vector<double> m_vec;
  SmallStorage(std::vector<double> vec) : m_vec(std::move(vec)) { }
};

std::vector<double> vec_from_data_source() {
  return std::vector<double>(); //only example!!
}

int main() {
  std::vector<double> vec = vec_from_data_source();
  if (vec.size() > 10000)
  {
    HugeStorage storage(std::move(vec));
    //do some things, but I gotta be careful I don't do anything to vec
  }
  else
  {
    SmallStorage storage(std::move(vec));
    //do some things, but I gotta be careful I don't do anything to vec
  }
  return 0;
}
4

2 に答える 2

11

変数を移動した後に誤って変数を使用した場合、コンパイラにエラー (または警告) を与えるように指示する方法はありませんか?

答えは「いいえ、方法はありません」です(少なくとも私の知る限り、現在利用可能なコンパイラはそのようなオプションを提供しておらず、正当な理由があります - 以下を参照してください)。

仮にそれが可能だったとしても、なぜこの場合に警告、さらに悪いことにエラーが発生することを期待するのでしょうか? まず、整数から移動することは、それをコピーすることと何の違いもありません。

次に、ほとんどの型では、その型の移動元オブジェクトを割り当てることは完全に正当な操作です。これは、 のような基本型には常に当てはまり、intには間違いなく当てはまりますがstd::vector、他の型には当てはまらない場合があります。

一般に、moved-from オブジェクトの割り当てが有効かどうかは、その型の移動操作の特定の事後条件と、代入演算子の前提条件 (標準ライブラリの型の代入演算子には前提条件がありません) に依存します。左側の引数)。これは、コンパイラが一般的なケースでチェックできないものです。

したがって、次の場合:

  1. 移動代入または移動コンストラクターが移動元オブジェクトを未指定の状態に置くオブジェクトから移動します(これは の場合ですstd::vector)。
  2. そのオブジェクトの状態に関する前提条件を使用して任意の関数を呼び出します (これは、への代入には当てはまりませんstd::vector)。

それは確かに悪いでしょう。一方、コンパイラには、プログラムのセマンティック分析を実行して、これが該当するかどうかを調べる方法がありません。

A x, y;
...
if (complicatedCondition())
{
    y = move(x);
} 

foo(x); // Did I move from x? And if so, is it safe to call foo()?

さらに、C++ の哲学は、強力な機能と (ほとんどの場合) 設計ガイドラインを提供することですが、実際にそうしようとしている場合は、「足を撃ちましょう」ということを忘れないでください。

C++ で実行できる危険な、無意味なことさえあります(同じポインターを 2 回試みた場合、コンパイラーは警告またはエラーを出しますdeleteか?) が、言語自体がそれらの実行を妨げることはありません。自分が何をしているかを本当に、本当に知っているという仮定の下で。

于 2013-02-25T20:08:33.130 に答える
5
//do some things, but I gotta be careful I don't do anything to vec

明確化: 前提条件が必要なことは何もしないように注意する必要がありますvec。前提条件を必要としないものなら何でもできます。たとえば、新しい値を割り当てることができます。を呼び出すことができます。を呼び出すことができます。ただし、そのメンバー関数には前提条件があるため、呼び出さないでください。vecvecvec.clear()vec.size()vec.pop_back()

于 2013-02-25T20:34:08.383 に答える