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

@更新

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

让我把我的问题说得更清楚。在 #1 中,doubleint(2) 创建一个时间,然后bar<const double &>从它创建 a 并复制到foo中,而在 #2 中,bar<int>创建一个时间,并从的 ctor 中double的成员创建一个时间。似乎时间在#2中被破坏,而在#1中却没有。为什么?我认为它们都是完整表达的一部分,并且会一直存在到返回。bar<int>bar<const double&>doublefoobar

Tim 说:“编译器足够聪明,可以将这个 2 视为 double 而不是 int。”。所以我写信int i = 2;并传递i给这两个电话,但事情像以前一样继续。我在 VS2008 中使用调试模式完成了它。

4

4 回答 4

1

在 #2 中,从 的参数tuple<double const&>构造一个时间。在' 的构造之前,从 的 int 成员构造一个时间 double(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&). 为了做到这一点,doublefull-expression 创建了一个临时的foo(boost::tuple<const double&>(2))。然后创建一个临时boost::tuple<const double&>的。它有一个绑定到临时的引用成员doublefoo两个临时变量都存在,直到完整表达式 #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-initializermember1(int_tup.member1_)int值转换为临时值并将其double绑定double到类引用成员。这个临时double是由 full-expression 创建的member1_(int_tup.member1_),而不是由 full-expression创建的foo(boost::make_tuple(2))。mem-initializers 的一个特殊例外保证了double在创建它的构造函数结束之前临时是可以的,但是不能保证它在foo被调用时仍然有效。

所以重要的区别是语句#1double自己创建临时变量,但语句#2 间接导致double在另一个函数中创建临时变量。确切地说,哪个完整表达会创建一个临时对象,这会影响该临时对象的寿命。

于 2010-12-25T03:14:49.753 回答
0

我相信第 1 行是可以的,因为允许 const 引用来引用临时对象。有人可能会引用标准。

于 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 回答