隐式铸造临时对象的生命周期

发布于 2024-10-09 01:39:58 字数 1384 浏览 0 评论 0原文

我看过这个问题。 看来,无论进行何种强制转换,临时对象都会“生存”,直到评估完整表达式为止。 但在以下场景中:

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 并且只有 2 个失败。

@update

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

让我把我的问题说得更清楚。在 #1 中,从 int (2) 创建一个时间 double,然后从中创建一个 bar并复制到 foo 中,而在 #2 中,创建了一个临时 bar 并从 < 的成员创建了一个临时 double bar 的构造函数中的 code>bar。似乎时间 double 在 #2 中的 foo 中被破坏,而在 #1 中则没有。为什么?我认为它们都是完整表达式的一部分,并且应该存在直到 bar 返回。

Tim 说“编译器足够聪明,可以将这个 2 视为 double 而不是 int。”。所以我写了 int i = 2; 并将 i 传递给这两个调用,但事情还是像以前一样进行。我是在VS2008下用调试模式做的。

I have seen this question.
It seems that regardless of the cast, the temporary object(s) will "survive" until the fullexpression evaluated.
But in the following scenario:

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 run well, but 2 do not.
And MSVC gave me a warning about 2: "reference member is initialized to a temporary that doesn't persist after the constructor exits"

Now I am wondering why they both make a temporary double object and pass it to bar<const double&> and only 2 failed.

@update

I use struct bar instead of boost::tuple in the original post, hope it will be more familiar to others.

Let me make my question more clear. In #1, a temporal double is created from int (2) and then a bar<const double &> is created from it and copied into foo, while in #2, a temporal bar<int> is created and a temporal double is created from the member of bar<int> in the ctor of bar<const double&>. It seems that the temporal double is destructed in foo in #2 while do not in #1. Why? I think they are all part of the fullexpression and shall be exist until bar return.

Tim says "The compiler is smart enough to treat this 2 as a double instead of an int.". so I wrote int i = 2; and passed i to both of the two calls, but things go on like before. I made it in VS2008 with debug mode.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

|煩躁 2024-10-16 01:39:58

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

.#2 调用 boost::tuple::tuple(const boost::tuple&)。此表达式创建一个临时 boost::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。确切地哪个完整表达式创建一个临时对象会影响该临时对象的生存时间。

.#1 calls boost::tuple<const double&>::tuple(const double&). In order to do this, a temporary double is created by the full-expression foo(boost::tuple<const double&>(2)). Then a temporary boost::tuple<const double&> is created. It has a reference member which is bound to the temporary double. Both temporaries exist until full-expression #1 is done, and is still valid when foo is called.

.#2 calls boost::tuple<const double&>::tuple(const boost::tuple<int>&). This expression creates a temporary boost::tuple<int>. The lifetime of that temporary is similarly not a problem. But consider what happens when that tuple constructor is called. Simplified / pseudocode classes:

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_) {}
  // ...
};

The mem-initializer member1(int_tup.member1_) converts the int value to a temporary double and binds that double to the class reference member. This temporary double is created by the full-expression member1_(int_tup.member1_), not by the full-expression foo(boost::make_tuple(2)). A special exception for mem-initializers guarantees that the temporary double is okay until the end of the constructor in which it was created, but then there's no guarantee it's still valid when foo is called.

So the important difference is that statement #1 creates the temporary double itself, but statement #2 indirectly causes a temporary double to be created within another function. Exactly which full-expression creates a temporary has an impact on how long that temporary will live.

信愁 2024-10-16 01:39:58

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

希望这有帮助

In #2, a temporal tuple<double const&> is constructed from tuple<int>
as the argument n for foo.
Before tuple<double const&>'s construction, a temporal double(D) is
constructed from an int member of tuple<int>, and the double const&
member is initialized as D.
Temporal objects constructed to prepare function arguments are destructed
when the function call is completed.
So, D is destructed when tuple<double const&>'s constructor finishes.

Hope this helps

离不开的别离 2024-10-16 01:39:58

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

I believe line #1 is OK because const references are allowed to refer to temporaries. Somebody can probably quote the standard on that.

黯然#的苍凉 2024-10-16 01:39:58

前言:我不是 Boost 或 Tuple 专家。我也从来没有用过。无论如何,我会尽力提供帮助。

在我看来,boost::make_tuple(2)正在返回一个tuple。但是,似乎进行了隐式转换以匹配您的 foo 实现,在此期间它可能会尝试获取临时地址(将 int 转换为 >const double&) 不恰当。

您是否尝试过显式转换您的 make_tuple

再说一遍,我不是增强或元组专家,但我会尝试:

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

或者

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

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

Preface: I am not a Boost or Tuple expert. I've never used either. I will attempt to be helpful anyway.

It appears to me that boost::make_tuple(2) is returning a tuple<int>. However, there appears to be an implicit cast done to match your foo implementation, during which time it may be attempting to take the address of the temporary (converting int to const double&) inappropriately.

Have you tried explicitly casting your make_tuple?

Again, I'm not a boost or tuple expert, but I would try:

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

or

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

I admit I'm taking an educated guess here in an attempt to help, so I don't promise this is the right tree to bark up.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文