gpt4 book ai didi

c++ - 右值数据成员初始化 : Aggregate initialization vs constructor

转载 作者:可可西里 更新时间:2023-11-01 18:36:39 25 4
gpt4 key购买 nike

对于下面的代码:

#include <iostream>
#include <memory>
#include <string>
using namespace std;

struct Foo {
string tag;

Foo(string t): tag(t){
cout << "Foo:" << tag << endl;
}
~Foo() {
cout << "~Foo:" << tag << endl;
}
};

struct Bar {
Foo&& foo;
};

struct Baz{
Foo&& foo;
Baz(Foo&& f):foo(std::move(f)){

}
};

int main() {
Bar bar{Foo("Bar")};
Baz baz{Foo("Baz")};
cin.get();
}

结果(g++ 7.1.0):

Foo:Bar
Foo:Baz
~Foo:Baz

我们可以看到 bar 成功地延长了临时 Foo 的生命周期,但是 baz 没有这样做。两者有什么区别?如何正确实现 Baz 的构造函数?

编辑:实际上 VC++2017 给出:

Foo:Bar
~Foo:Bar
Foo:Baz
~Foo:Baz

所以我猜整个事情都不可靠。

最佳答案

Baz 是一个带有构造函数的类。因此,当你使用列表初始化时,编译器会寻找一个构造函数来调用。该构造函数将被传递给 braced-init-list 的成员,或者一个 std::initializer_list 如果匹配列表的成员。在任何一种情况下,临时绑定(bind)到函数参数的规则都有效([class.temporary]/6.1):

A temporary object bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.

但是,Bar 不是具有构造函数的类;它是一个集合体。因此,当您使用列表初始化时,您(在本例中)调用了聚合初始化。因此,成员引用将直接绑定(bind)到给定的纯右值。规则是 ([class.temporary]/6):

The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:

后面是3条不适用本案的异常(exception)情况(包括上面引用的6.1)。

引用 Bar::foo 的生命周期延伸到 main 的末尾。在 cin.get() 返回之前不会发生这种情况。


How can I implement the constructor of Baz correctly?

如果“正确地”是指“像 Bar”,那么您不能。聚合可以做非聚合不能做的事情;这是其中之一。

类似这样的:

struct Types { int i; float f };
using Tpl = std::tuple<int, float>;

int &&i1 = Types{1, 1.5}.i;
int &&i2 = std::get<0>(Tpl{1, 1.5});

i2 是对已销毁临时对象的子对象的悬挂引用。 i1 是对生命周期已延长的临时对象的子对象的引用。

有些事情您无法通过函数完成。

关于c++ - 右值数据成员初始化 : Aggregate initialization vs constructor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45293841/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com