2013-02-25 7 views
7

このmove'ed:は、エラー、または少なくとも警告を取得::他の場所

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; 
} 
+2

変数は移動されておらず、値は移動していません。新しい値を割り当てることに間違いはありません。 –

+0

あなたは何の「トラブル」を予見していますか、あなたが見せているコードの*実際の問題は何ですか? –

+0

@NikBougalisより現実的な例で更新されました – user2015453

答えて

10

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

答えはは(少なくとも私の知る限り、ない現在利用可能なコンパイラは、このようなオプションを提供し、正当な理由のために - 下記参照)、「いいえ、方法がない」です。

このような場合でも、なぜこの場合警告が表示されるか、さらに悪いエラーが発生すると思われますか?まず第一に、整数から移動することはそれをコピーすることと変わりありません。

第2に、ほとんどのタイプの場合、そのタイプの移動元オブジェクトを割り当てることは完全に法的な操作です。 intのような基本型には常に当てはまり、std::vectorというのは間違いありませんが、他の型には当てはまらないかもしれません。

一般に、移動元オブジェクトの割当が正当であるかどうかは、その型の移動操作の特定の後条件および割当演算子の前提条件(標準ライブラリのタイプの割当演算子左側の引数には前提条件がない)。コンパイラが一般的なケースでチェックできないものです。

あなたがした場合従って、:のための移動割り当て対象から

  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++で行うことができさえ無意味なものは(あなたが二回deleteに同じポインタをしようとした場合、あなたのコンパイラは、あなたに警告、またはエラーを与えるのだろうか?)が、言語自体は」勝ちましたあなたが本当にあなたがしていることを本当に知っているという仮定の下で、あなたがそれらをやるのを妨げます。

+0

ライブラリ型の場合、オブジェクトが* assignable-to *であるという保証はなく、破壊可能であるということだけです。つまり、多くの図書館の実装は、標準が要求する以上の保証を提供するでしょう。 –

+6

@DavidRodríguez-dribeas:17.6.5.15/p1は、移動されたすべてのstd :: libタイプが有効であるが不特定の状態になることを保証します。これは、型が代入文のlhsの前提条件を持っていない限り、それが移動された後でも代入できることを意味します。このブランケット文はstd-​​libの型に適用され、一般的な型には適用されないことに注意してください。そして私は割り当てられている前提条件を持っているstd :: typeを認識していません。 –

+1

@HowardHinnant:ありがとうございます。 –

0

私は、変数のスコープの代替としての動きを使用しようとしていると思います。

int main() 
{ 
    { 
    int i = 2; 
    foo(std::move(i)); 
    } 
    i = 3; // error! 
    return 0; 
} 
+0

さて、最も単純なケースで動作しますが、それは何かです... – user2015453

+0

私はあなたが間違った方法で移動意味を使用すると思う、範囲の交換のいくつかの種類、私の答えは、 – Slava

5
//do some things, but I gotta be careful I don't do anything to vec 

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

+2

誰にとっても分かりにくい場合は、前提条件を確認することなく前提条件を必要とすることは一切できないことを明確にします。 'vec.empty()'を呼び出すと、前提条件が満たされていることが分かります。 –

+1

はい、うれしく思います。ジョナサン。 –

関連する問題