简体   繁体   English

rvalue数据成员初始化:聚合初始化与构造函数

[英]rvalue data member initialization: Aggregate initialization vs constructor

For the code below: 对于以下代码:

#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();
}

result(g++ 7.1.0): 结果(g ++ 7.1.0):

Foo:Bar
Foo:Baz
~Foo:Baz

We can see that bar successfully extend the lifetime of a temporary Foo but baz failed to do so. 我们可以看到bar成功延长了临时Foo的生命周期,但baz未能这样做。 What is the difference between the two? 两者有什么区别? How can I implement the constructor of Baz correctly? 如何正确实现Baz的构造函数?

Edit: actually VC++2017 gives: 编辑:实际上VC ++ 2017给出:

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

So I guess the whole thing is not reliable. 所以我猜整件事情都不可靠。

Baz is a class with a constructor. Baz是一个带有构造函数的类。 Therefore, when you use list initialization, the compiler will look for a constructor to call. 因此,当您使用列表初始化时,编译器将查找要调用的构造函数。 That constructor will be passed the members of the braced-init-list, or a std::initializer_list if one matches the members of the list. 该构造函数将传递braced-init-list的成员,或者如果匹配列表成员则传递std::initializer_list In either case, the rules of temporary binding to function parameters are in effect ([class.temporary]/6.1): 在任何一种情况下,临时绑定到函数参数的规则都有效([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. 绑定到函数调用(5.2.2)中的引用参数的临时对象将持续存在,直到包含该调用的完整表达式完成。

However, Bar is not a class with a constructor; 但是, Bar不是带构造函数的类; it is an aggregate. 它是一个聚合。 Therefore, when you use list initialization, you (in this case) invoke aggregate initialization. 因此,当您使用列表初始化时,您(在本例中)将调用聚合初始化。 And therefore, the member reference will be bound to the given prvalue directly. 因此,成员引用将直接绑定到给定的prvalue。 The rule for that is ([class.temporary]/6): 对此的规则是([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: 绑定引用的临时对象或绑定引用的子对象的完整对象的临时对象在引用的生命周期内持续存在,除了:

Followed by 3 exceptions which do not apply to this case (including 6.1, quoted above). 其次是3个不适用于此案例的例外情况(包括上文引用的6.1)。

The lifetime of the reference Bar::foo extends to the end of main . 参考Bar::foo的生命周期延伸到main的末尾。 Which doesn't happen until cin.get() returns. cin.get()返回之前不会发生这种情况。


How can I implement the constructor of Baz correctly? 如何正确实现Baz的构造函数?

If by "correctly", you mean "like Bar ", you cannot. 如果“正确”,你的意思是“像Bar ”,你不能。 Aggregates get to do things that non-aggregates can't; 聚合可以做非聚合不能做的事情; this is one of them. 这是其中之一。

It's similar to this: 它与此类似:

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 is a dangling reference to a subobject of a destroyed temporary. i2是对被破坏的临时对象的子对象的悬空引用。 i1 is a reference to a subobject of a temporary whose lifetime was extended. i1是对生命周期延长的临时子对象的引用。

There are some things you just can't do through functions. 有些事情是你无法通过功能完成的。

To point out the difference between VC++ and g++, I think the below have some information on it https://stackoverflow.com/a/26581337/4669663 要指出VC ++和g ++之间的区别,我认为下面有一些关于它的信息https://stackoverflow.com/a/26581337/4669663

Since the move constructor is added by default, this 由于默认情况下添加了移动构造函数,因此

Foo:Bar
~Foo:Bar - Move constructor generated by VC
Foo:Baz
~Foo:Baz

"Rvalue references v3.0" adds new rules to automatically generate move constructors and move assignment operators under certain conditions. “Rvalue references v3.0”添加了新规则,以自动生成移动构造函数并在特定条件下移动赋值运算符。 This is implemented in Visual Studio 2015. 这是在Visual Studio 2015中实现的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM