1. ホーム
  2. c++

[解決済み】なぜ、constでない参照は一時的なオブジェクトにバインドできないのでしょうか?

2022-04-03 13:24:32

質問

一時的なオブジェクトへのconstでない参照を取得することができないのはなぜですか? どの関数 getx() を返すのでしょうか?明らかにC++標準では禁止されています。 しかし、私はこのような制限の目的に興味があります。 参照ではない を標準化した。

struct X
{
    X& ref() { return *this; }
};

X getx() { return X();}

void g(X & x) {}    

int f()
{
    const X& x = getx(); // OK
    X& x = getx(); // error
    X& x = getx().ref(); // OK
    g(getx()); //error
    g(getx().ref()); //OK
    return 0;
}

  1. オブジェクトのライフタイムが原因でないことは明らかです。 オブジェクトへの常時参照は 禁止されていない は、C++標準によって
  2. 上記のサンプルでは、定数でない関数の呼び出しが許可されているため、一時的なオブジェクトが定数でないことは明らかです。例えば ref() は一時的なオブジェクトを変更することができます。
  3. さらに ref() を使えば、コンパイラーをだまして、この一時的なオブジェクトへのリンクを取得することができ、これで問題は解決です。

おまけに

const参照に一時的なオブジェクトを代入すると、このオブジェクトの寿命が延びるそうです"const参照以外については何も言われていませんが"。 私の 追加質問 . 次の代入は、一時的なオブジェクトの寿命を延長しますか?

X& x = getx().ref(); // OK

解決方法は?

ここから Visual C++のブログでrvalueの参照について書かれた記事 :

<ブロッククオート

... C++は、あなたが誤って テンポラリーを変更しても、直接 に対してconstでないメンバ関数を呼び出す 変更可能なr値は明示的であり、そのため 許される.

基本的に、テンポラリは一時的なオブジェクトであり、今にも死んでしまうという理由から、変更しようとしないほうがよいでしょう。コンストラストでないメソッドを呼び出すことが許されているのは、自分が何をしているかを知っていて、それを明示する限り、いくつかの "愚かな" を行うことが許されているからです(例えば reinterpret_cast を使うなど)。しかし、temporaryをconstでない参照にバインドしてしまうと、temporaryであることを完全に忘れてしまったために、オブジェクトの操作が消えてしまうということがあり得ます。

私があなたなら、関数の設計を見直しますね。なぜg()は参照を受け入れるのでしょうか?パラメータを変更するのでしょうか?もしそうなら、なぜtemporaryを渡そうとするのでしょうか?なぜ、getx()はtemporaryを返すのですか?あなたの実際のシナリオと、あなたが達成しようとしていることを私たちと共有すれば、それを行う方法についていくつかの良い提案を得ることができるかもしれません。

言語に逆らったり、コンパイラーを騙したりしても、問題が解決することはほとんどなく、たいていの場合、問題が発生します。


編集:コメント中の質問に対応します。 1) X& x = getx().ref(); // OK when will x die? - これはまさに私が言っている「言語に反する」ということなので、私は知りませんし、気にしません。言語では、quot;temporaryは文の終わりで死ぬ。ただし、const参照に束縛されている場合は、その参照がスコープ外に出たときに死ぬ。この規則を適用すると、xはconst参照に束縛されていない(コンパイラはref()が何を返すか知らない)ので、次の文の始めにはすでに死んでいるようです。ただし、これは単なる推測に過ぎない。

2) 私は目的を明確に述べました:テンポラリーを修正することは許されていません、なぜなら意味がないからです(C++0xのr値参照を無視する)。C++0xのrvalueの参照を無視したもの)。

3) さて、もし私の言うとおりなら X& x = getx().ref(); が文末に死ぬと、問題は明白です。

とにかく、あなたの質問とコメントからすると、これらの余分な答えでさえ、あなたを満足させることはできないと思います。C++委員会は、テンポラリを変更するのは意味がないと判断し、非const参照へのバインディングを禁止しました。このとき、コンパイラの実装や歴史的な問題が絡んでいたかもしれません。しかし、ある特殊なケースが発生し、どう考えてもconstでないメソッドを呼び出して直接変更することを認めることになった。でも、それは例外で、一般的にはテンポラリの改変は許されない。そう、C++はそのくらい変なことが多いのです。