1

私はこの質問を見ました。キャストに関係なく、一時オブジェクトは完全な式が評価されるまで「存続」するようです。しかし、次のシナリオでは:

template<class T>
struct bar {
    T t;
    bar(T t) : t(t) {}
    template<class U>
    bar(bar<U> other) : t(other.t) {}
};
void foo(bar<const double&> b) {
    printf("%lf\n", b.t);
}
int main() {
    foo(bar<const double&>(2));//#1
    foo(bar<int>(2));          //#2
    return 0;
}

1つはうまく動作しますが、2つはそうではありません。そしてMSVCは私に2についての警告を与えました:「参照メンバーはコンストラクターが終了した後に持続しない一時的なものに初期化されます」

今、私はなぜ彼らが一時doubleオブジェクトを作成してそれを渡すのか疑問に思っていますがbar<const double&>、2つだけが失敗しました。

@アップデート

元の投稿の代わりに構造体バーを使用boost::tupleしています。他の人に親しまれていることを願っています。

私の質問をもっと明確にしましょう。#1では、(2)doubleからテンポラルが作成され、そこからaが作成されて、にコピーされます。#2では、テンポラルが作成され、のctorのメンバーからテンポラルが作成されます。#1ではなく#2でテンポラルが破壊されているようです。なんで?それらはすべて完全な表現の一部であり、戻るまで存在するはずだと思います。intbar<const double &>foobar<int>doublebar<int>bar<const double&>doublefoobar

ティムは、「コンパイラは、この2をintではなくdoubleとして扱うのに十分賢い」と述べています。だから私は2つの呼び出しの両方に書き込みint i = 2;、パスiしましたが、物事は以前と同じように進行します。VS2008でデバッグモードで作成しました。

4

4 に答える 4

1

#2 では、 の引数としてテンポラルtuple<double const&>が構築されます。の構築前に、 の int メンバからテンポラル double(D) が構築され、 メンバは D として初期化されます。関数の引数を準備するために構築されたテンポラル オブジェクトは、関数呼び出しが完了すると破棄されます。したがって、 Dのコンストラクターが終了すると、 D は破棄されます。tuple<int>nfootuple<double const&>tuple<int>double const&tuple<double const&>

お役に立てれば

于 2010-12-24T23:13:34.657 に答える
1

.#1 コールboost::tuple<const double&>::tuple(const double&). これを行うためにdouble、 full-expression によって一時が作成されますfoo(boost::tuple<const double&>(2))。次に、一時boost::tuple<const double&>が作成されます。一時的な にバインドされている参照メンバーがありdoubleます。foo両方の一時変数は完全な式 #1 が完了するまで存在し、が呼び出されたときにも有効です。

.#2 コールboost::tuple<const double&>::tuple(const boost::tuple<int>&). この式は、一時的な を作成しboost::tuple<int>ます。その一時的な有効期間も同様に問題ではありません。しかし、そのtupleコンストラクターが呼び出されたときに何が起こるかを考えてみてください。簡略化された/疑似コード クラス:

template<> class tuple<int> {
  private:
    int member1_;
  //...
};

template<> class tuple<const double&> {
  private:
    const double& member1_;
  public:
    tuple(const tuple<int>& int_tup) : member1_(int_tup.member1_) {}
  // ...
};

mem-initializerは値を一時値にmember1(int_tup.member1_)変換し、それをクラス参照メンバーにバインドします。このテンポラリは、 full-expressionではなく、full-expression によって作成されます。mem-initializers の特別な例外により、一時が作成されたコンストラクターの最後まで問題ないことが保証されますが、呼び出されたときにまだ有効であるという保証はありません。intdoubledoubledoublemember1_(int_tup.member1_)foo(boost::make_tuple(2))doublefoo

したがって、重要な違いは、ステートメント #1 は一時double自体を作成しますが、ステートメント #2 は間接的に一時doubleを別の関数内に作成することです。どの完全式がテンポラリを作成するかは、そのテンポラリが存続する期間に影響を与えます。

于 2010-12-25T03:14:49.753 に答える
0

const 参照は一時参照を許可されているため、1 行目は問題ないと思います。誰かがおそらくそれに関する標準を引用できます。

于 2010-12-24T15:23:28.450 に答える
0

序文: 私は Boost や Tuple の専門家ではありません。私も使ったことはありません。とにかくお役に立てるように努めます。

boost::make_tuple(2)を返しているように見えますtuple<int>。ただし、実装に一致するように暗黙のキャストが行われているようfooです。その間、一時的な (に変換intするconst double&) 不適切なアドレスを取得しようとしている可能性があります。

を明示的にキャストしようとしましたmake_tupleか?

繰り返しますが、私はブーストやタプルの専門家ではありませんが、試してみます:

 foo(boost::make_tuple(boost::cref((double)2)));//#2

また

 foo(boost::make_tuple((const double&)2);//#2

私は助けようとしてここで経験に基づいた推測を行っていることを認めているので、これが吠えるのに適したツリーであるとは約束しません.

于 2010-12-24T15:47:41.703 に答える