10

あるオブジェクト (整数変数など) への参照を「記憶」するクラスがあります。すぐに破棄される値を参照することはできません。クラスのユーザーが誤って参照しないようにする方法を探しています。

右辺値参照のオーバーロードは、一時的なものが渡されるのを防ぐ良い方法ですか?

struct HasRef {
    int& a;
    HasRef(int& a):a(a){}
    void foo(){ a=1; }
};


int main(){
    int x=5;
    HasRef r1(x);
    r1.foo();  // works like intended.

    HasRef r2(x+4);
    r2.foo(); // dereferences the temporary created by x+4

 }

プライベートな右辺値のオーバーロードはできますか?

 struct HasRef {
   int& a;
   HasRef( int& a ):a(a){}
   void foo(){ a=1; }
 private: 
   HasRef( int&& a );
 };

 ... HasRef r2(x+1); // doesn't compile => problem solved?

私が見ていない落とし穴はありますか?

4

4 に答える 4

7

consttype のインスタンスへの参照をBclassに格納する必要がある場合は、インスタンスの有効期間がインスタンスの有効期間を超えているAことを確認したいはずです。AB

B b{};
A a1{b}; // allowed
A a2{B{}}; // should be denied
B const f() { return B{}; } // const result type may make sense for user-defined types
A a3{f()}; // should also be denied!

これを可能にするに= delete;は、右辺値 ( と の両方) を受け入れることができるすべてのコンストラクターのオーバーロードを明示的に行う必要がconst &&あり&&ます。これを達成するには、コンストラクターのバージョン= delete;のみにする必要があります。const &&

struct B {};

struct A
{
    B const & b;
    A(B const & bb) : b(bb) { ; } // accepts only `B const &` and `B &`
    A(B const &&) = delete; // prohibits both `B &&` and `B const &&`
};

このアプローチにより、コンストラクターにあらゆる種類の右辺値を渡すことを禁止できます。

これは、組み込みスカラーに対しても機能します。たとえば、double const f() { return 0.01; }次のような警告が表示されます。

警告: 戻り型の 'const' 型修飾子は効果がありません [-Wignored-qualifiers]

コンストラクターのバージョン= delete;のみの場合でも効果があります。&&

struct A
{
    double const & eps;
    A(double const & e) : eps(e) {} // binds to `double const &`, `double &` AND ! `double const &&`
    A(double &&) = delete; // prohibit to binding only to `double &&`, but not to `double const &&`
};

double const get_eps() { return 0.01; }

A a{0.01}; // hard error
A a{get_eps()}; // no hard error, but it is wrong!

非変換コンストラクター (つまり、非単項) の場合、問題があり= delete;ます。次のように、コンストラクターの組み合わせで可能なすべてのバージョンに対して -d バージョンを提供する必要がある場合があります。

struct A
{
    A(B const &, C const &) {}
    A(B const &&, C const &&) = delete;
    // and also!
    A(B const &, C const &&) = delete;
    A(B const &&, C const &) = delete;
};

次のような大文字と小文字の混合を禁止します。

B b{};
A a{b, C{}};
于 2016-12-23T13:06:39.533 に答える
3

コードが無効であるという事実を無視して、プライベート オーバーロードに関する質問に答えるだけです...

C++11 では、プライベート関数よりも削除された関数を好みます。あなたが実際にそれを呼び出すことができないことは、もう少し明白です(あなたがクラスのメンバーまたは友人であっても)。

注意: 削除されたコンストラクターはHasRef(int&&)=delete、ここでは選択されません。

int i;
HasRef hr(std::forward<const int>(i));

const int&&typeの引数を使用すると、HasRef(const int&)コンストラクターではなく、コンストラクターが使用されHasRef(int&&)ます。この場合、i実際には左辺値であるため問題ありませんが、一般的にはそうではない可能性があるため、const右辺値参照が役立つ非常にまれなケースの 1 つになる可能性があります。

HasRef(const int&&) = delete;
于 2012-06-20T20:47:03.880 に答える
2

それはコンパイルされるべきではありません。優れた C++ コンパイラ (または、私が今まで見たほとんどすべての C++ コンパイラ) は、それを防ぐことができます。

于 2012-06-20T20:42:16.150 に答える
0

MSVSでコンパイルしていると思います。その場合、言語拡張機能をオフにすると、エラーが発生するはずです。

それ以外の場合、参照をマークしてもconst、コンストラクターが終了するまで一時的な寿命が延びるわけではありません。その後、無効なオブジェクトを参照します。

于 2012-06-20T20:56:28.327 に答える