2016-12-08 19 views
1

この例を考えてみ検出:shortoption_sは、一時オブジェクトを使用してintに変換される:がCONST参照の暗黙的型変換

#include <iostream> 

struct Thing 
{ 
    Thing(int const& ref) : ref(ref) {} 
    int const& ref; 
}; 

int main() 
{ 
    int option_i = 1; 
    short option_s = 2; 

    Thing thing_i(option_i); 
    Thing thing_s(option_s); 

    std::cout << thing_i.ref << "\n"; // 1 
    std::cout << thing_s.ref << "\n"; // 2 

    option_i = 10; 
    option_s = 20; 

    std::cout << thing_i.ref << "\n"; // 10 
    std::cout << thing_s.ref << "\n"; // 2 <<< !!! 
} 

、私はこのケースでWHYを理解します。その一時的な参照は、次いで

// Thing thing_s(option_s); 
int __temporary = option_s; 
Thing thing_s(__temporary); 

に相当即ち、コンストラクタThing::Thingに渡され、違いを見つけることは非常に難しいしかし、これは多くの場合、所望されないかもしれません。 この場合、テンポラリはまだ少なくとも生きていますが、 ですが、これは一時的なダンピングリファレンスとなることもあります。

このようなconst-reference-to-temporary caseを検出する方法(設計パターン、gccコンパイラオプション、静的解析ツールなど)を知っていますか?

このようなケースを検出するためにconst-correctnessを犠牲にしますか?

答えて

3

ちょうど別のコンストラクタを書いて、としてそれを=deleteをマーク:あなたはint以外任意の引数を渡す場合さて、あなたはコンパイルエラーを取得します

template<typename T> 
Thing(T const &) = delete; 

Thing thing_s(option_s); //error 

あなただけshort(または知らタイプのセット)を削除するをしたい場合は、この使用することができます:あなたの基本的なアイデアを提供します

Thing(short const &) = delete; 
Thing(long const &) = delete; //lets disable long as well. 

希望を。

+0

あなたのオプションはおそらく最適ですが、SFINAE経由でコンストラクタを削除することもできます。コンストラクタをテンプレート化し、 'enable_if'を使ってそれが' int'であることを確認します。 –

+1

@CrazyEddie:それを行う方法は複数あります。私はこのアプローチが最も清潔であることを知ります。また、呼び出すコンストラクタ/関数が削除されたことを示すため、「禁止された」型が認識されます。そして、コンパイラはより多くのオーバーロードを検索することを止めます。それは**フェイル・ファースト**アプローチになります。 – Nawaz

+1

@CrazyEddie:明示的に削除すると良いエラーメッセージが表示されますが、コンストラクタがないと非常に難解かもしれません。 –

1

参照をバインドするクラスのコンストラクタを定義するための良い方法は、アドレスで引数を取ることです。

struct Foo 
{ 
    Bar const & ref; 
    Foo(Bar const * b) : ref(*b) {} 
}; 

使用法:これは彼らの方法のうちに行くために、ユーザが必要と

Bar x; 
Foo y(&x);  // OK 
Foo z(&Bar{}); // error: cannot take address of prvalue 

価値観のアドレスを入手して、すでに存在するオブジェクトのアドレスを期待していることを明確に伝え、おそらくインスタンスの生存期間を過ぎて生き続けていると考えられます。

+0

ただし、コンストラクタ内のポインタの有効性をチェックする必要があります。 – mbschenkel

+0

@mbschenkel:一般的にポインタの有効性をチェックすることはできませんので、気にしません。前提条件を文書化することができます(「bは逆参照可能でなければなりません」)。 –

関連する問題