Denis
Denis

Reputation: 3082

Member's destructor calling from default constructor

class Part
{
public:
    ~Part() = delete;
};

class CL
{
public:
    CL(){} //error: deleted destructor call
    ~CL();
    Part part;
};

int main()
{
}

This code gives an error associated with a Part's deleted destructor call. What is context in default constructor for members destructor calling?

P.S: As I know, destructor for a Part member must be called in ~CL(), but it is specially not defined for demonstrating, that default constructor forces it anywhere

Upvotes: 1

Views: 174

Answers (2)

xskxzr
xskxzr

Reputation: 13040

First, Part is a potentially constructed subobject of CL according to [special]p5.

For a class, its non-static data members, its non-virtual direct base classes, and, if the class is not abstract, its virtual base classes are called its potentially constructed subobjects.

So the destructor for Part is potentially invoked according to [class.base.init]p12, regardless of the existence of nonexcept or not.

In a non-delegating constructor, the destructor for each potentially constructed subobject of class type is potentially invoked.

Therefore the program is ill-formed according to [class.dtor]p12.

A program is ill-formed if a destructor that is potentially invoked is deleted or not accessible from the context of the invocation.

Note even though the deleted destructor is not actually invoked, the program is ill-formed as long as the destructor is potentially invoked.

Upvotes: 1

François Andrieux
François Andrieux

Reputation: 29022

Every constructor needs to have access to it's members' destructors. When a constructor throws an exception, it must be able to destroy every member that was initialized before the exception was thrown. You can verify that this is true for every constructor. If you try adding arbitrary arguments to the constructor, the error still occurs, even with copy and move constructors.

As it was mentioned in the comments, CL() = default; doesn't produce the error. This is because CL() = default; simply causes the compiler to produce the implicit default constructor it would normally generate. In this case, it appears the CL has a deleted implicitly-declared default constructor, meaning the automatically generated implicit default constructor would be deleted. If you try the following, you see that the default constructor is not actually available :

#include <type_traits>

class Part
{
public:
    ~Part() = delete;
};

class CL
{
public:
    CL() = default;
    ~CL();
    Part part;
};

// This assert passes
static_assert(std::is_default_constructible<CL>::value == false, "");

However, I can't explain precisely why CL has a deleted implicitly-declared default constructor, nor can I explain why CL() noexcept {}; doesn't work.

Upvotes: 2

Related Questions