隐式铸造临时工的一生

时间:2010-12-24 15:05:15

标签: c++ casting temporary lifetime

我见过this question。 似乎无论演员如何,临时对象都将“存活”直到评估完全表达。 但在以下场景中:

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个失败。

@Update

我在原帖中使用struct bar而不是boost::tuple,希望对其他人更熟悉。

让我更清楚地提出我的问题。在#1中,从double(2)创建时间int,然后从中创建bar<const double &>并将其复制到foo中,而在#2中创建时间bar<int>已创建double,并在bar<int>的{​​{1}}的{​​{1}}成员中创建时间bar<const double&>。似乎时间double在#2中的foo中被破坏而在#1中没有被破坏。为什么?我认为它们都是完整性的一部分,并且在bar返回之前一直存在。

蒂姆说:“编译器非常聪明,可以将这个2视为双精度而不是整数。”所以我写了int i = 2;并将i传递给了两个电话,但事情就像以前一样。我是在VS2008中使用调试模式制作的。

4 个答案:

答案 0 :(得分:1)

在#2中,时间tuple<double const&>tuple<int>构成 作为n的参数foo。 在tuple<double const&>构造之前,时间双(D)是 从tuple<int>的int成员和double const&构造 成员初始化为D. 构造用于准备函数参数的时间对象被破坏 当函数调用完成时。 因此,当tuple<double const&>的构造函数完成时,D被破坏。

希望这有帮助

答案 1 :(得分:1)

。#1调用boost::tuple<const double&>::tuple(const double&)。为此,临时double由完整表达式foo(boost::tuple<const double&>(2))创建。然后创建临时boost::tuple<const double&>。它有一个绑定到临时double的引用成员。两个临时值都存在,直到完全表达#1完成,并且在调用foo时仍然有效。

。#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_)int值转换为临时double,并将double绑定到类引用成员。此临时double由完整表达式member1_(int_tup.member1_)创建,而不是由完整表达式foo(boost::make_tuple(2))创建。 mem-initializers的一个特殊例外保证临时double在创建它的构造函数结束之前是可以的,但是当调用foo时,不能保证它仍然有效。

因此,重要的区别在于语句#1创建了临时double本身,但语句#2间接导致在另一个函数中创建临时double。完全 完整表达式创建一个临时文件会影响该临时文件的生存时间。

答案 2 :(得分:0)

我相信第1行是正确的,因为允许const引用引用临时数。有人可能会引用这个标准。

答案 3 :(得分: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

我承认我在这里采取了有根据的猜测,试图提供帮助,所以我不保证这是正确的树。

相关问题