Constではない信じられないほどのConst参照

2018年7月13日公開-23件のコメント

毎日C++

NamedTypeライブラリで作業している間、私は困惑して唖然とした状況に遭遇しました:それが参照するオブジェクトの変更を可能にするconst参照。 const_castなし。 mutableなし。 袖の上の何もなし。

これはどうすればいいですか? そして、そのconst参照でconstを強制する方法は?

constではないconst参照

ここでは、この奇妙な参照が発生する状況の説明です。 次のラッパークラスを考えてみましょう:

template<typename T>class Wrapper{public: Wrapper(T const& value) : value_(value) {} T const& get() const { return value_; } private: T value_;};

このWrapperクラスはT型の値を格納し、get()メソッドを介してアクセスできます(それとは独立して、”get”が良い名前であるかどうか疑問に思っている場合は、こ 重要な部分は、get()メソッドはconst参照を返すため、格納された値への読み取り専用アクセスのみを提供することです。

それを確認するには、例えばintでテンプレートをインスタンス化しましょう。 get()メソッドを使用して格納された値を変更しようとすると、コンパイルに失敗します(下の実行ボタンをクリックしてみてください)。

私たちはget()を読み取り専用にしたいので、これは問題ありません。

しかし、今度はWrapperint&でインスタンス化しましょう。 このためのユースケースの一つは、コピーを避けるため、または例えばaの潜在的な変更を追跡することです。 次に、get()によって返されたconst参照を使用して格納された値を変更してみましょう:

そして、あなたが実行ボタンを押すと、あなたはそれが表示されます…それはコンパイルされます! そして、特別なことは何も起こらなかったように、const参照を介して変更された値を出力します。

これは不可解ではないですか? constが提供する安心感を感じませんか? 私たちは誰を信頼できますか?

この参照で何が起こっているのかを理解しようとしましょう。

Const参照またはconstへの参照ですか?問題の核心は、参照がconst参照であるが、constへの参照ではないということです。

それが何を意味するのかを下にするために、テンプレートのインスタンス化で何が起こっているのかを段階的に分解してみましょう。

get()メソッドはconst T&を返し、Ttemplate Tから来ます。 2番目のケースでは、Tint&なので、const T&const (int&) &です。

このconst (int&)を詳しく見てみましょう。 int&intを参照する参照であり、そのintを変更することが許可されています。 しかし、const (int&)は参照int&つまりconstであり、参照自体を変更することはできません。

最初に参照を変更するとはどういう意味ですか? 理論的には、それは別のオブジェクトを参照するか、何も参照しないことを意味します。 しかし、これらの可能性は両方ともC++では違法です。 それはそれの人生の全過程の間に同じオブジェクトを指します。

だからconstであることは、再バインドすることができないので、常にconstであるため、参照のためにあまり言いません。 これは、const (int&)が事実上int&と同じ型であることを意味します。

get()(int&) &に戻します。 そして、参照の崩壊のルールによって、これはint&です。

したがって、getint&を返します。 そのインターフェースはT const&と書かれていますが、実際はint&です。 本当に表現力のあるコードではありませんか?

const参照をconst

への参照にする方法今、問題を理解する最初のステップを過ぎているので、どうすれば修正できますか? つまり、get()を変更できない格納された値への参照を返すにはどうすればよいですか?

これを行う1つの方法は、参照の中にconstを明示的に挿入することです。 これを行うには、参照を削除し、constを追加し、参照を元に戻すことができます。 参照を削除するには、C++11ではstd::remove_referenceを使用し、Cではより便利なstd::remove_reference_tを使用します++14:

実行をクリックするとわかるように、Wrapperに格納されている値を変更しようとすると、予想されるコンパイルエラーが表示されるようになりました。

これは安全なように見えるコードですが、実際にはそうではなく、これが最も危険な種類であるため、この参照で何が起こっているのかを理解する

ページに埋め込まれた上記の遊び場のコードで遊ぶことができます。 そして、この問題の背後にある理由を理解するのを手伝ってくれたstack overflowユーザー rakete1111に大きな感謝します。

あなたも好きかもしれません

  • 最も厄介な解析:それを見つけてすぐに修正する方法

コメントを残す

メールアドレスが公開されることはありません。