Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can the type of braces influence object lifetime in C++?

A friend of mine showed me a program in C++20:

#include <iostream>

struct A
{
    A() {std::cout << "A()\n";}
    ~A() {std::cout << "~A()\n";}
};

struct B
{
    const A &a;
};

int main()
{
    B x({});
    std::cout << "---\n";
    B y{{}};
    std::cout << "---\n";
    B z{A{}};
    std::cout << "---\n";
}

In GCC it prints:

A()
~A()
---
A()
---
A()
---
~A()
~A()

https://gcc.godbolt.org/z/ce3M3dPeo

So the lifetime of A is prolonged in cases y and z.

In Visual Studio the result is different:

A()
~A()
---
A()
---
A()
~A()
---
~A()

So the lifetime of A is only prolonged in case y.

Could you please explain why the type of braces influences the object lifetime?

like image 925
Fedor Avatar asked Jul 10 '21 09:07

Fedor


People also ask

How can you extend the lifetime of an object?

The lifetime of a temporary object may be extended by binding to a const lvalue reference or to an rvalue reference (since C++11), see reference initialization for details.

What is lifetime of a local object?

The lifetime of a variable is the time during which the variable stays in memory and is therefore accessible during program execution. The variables that are local to a method are created the moment the method is activated (exactly as formal parameters) and are destroyed when the activation of the method terminates.

What is lifetime of local object in C++?

C/C++ use lexical scoping. The lifetime of a variable or object is the time period in which the variable/object has valid memory. Lifetime is also called "allocation method" or "storage duration."


Video Answer


1 Answers

Gcc is correct. The lifetime of the temporary will be extended only when using list-initialization syntax (i.e. using braces) in initialization of an aggregate.

(since C++20) a temporary bound to a reference in a reference element of an aggregate initialized using direct-initialization syntax (parentheses) as opposed to list-initialization syntax (braces) exists until the end of the full expression containing the initializer.

struct A {
  int&& r;
};
A a1{7}; // OK, lifetime is extended
A a2(7); // well-formed, but dangling reference

For direct initialization:

(emphasis mine)

otherwise, if the destination type is a (possibly cv-qualified) aggregate class, it is initialized as described in aggregate initialization except that narrowing conversions are permitted, designated initializers are not allowed, a temporary bound to a reference does not have its lifetime extended, there is no brace elision, and any elements without an initializer are value-initialized. (since C++20)

like image 121
songyuanyao Avatar answered Oct 19 '22 16:10

songyuanyao