Bill Kotsias
Bill Kotsias

Reputation: 3358

Aggregate initialization by-passes private class constructor

I always thought that aggregate initialization was to save coders from writing custom constructors. However, this seems to have "sneaked in" a "security by-pass" for private constructors.

Say I have class A which I only want to be created by class B.

struct A
{
  friend class B;
  const int i, k;
private:
  A () = default;
};

class B
{
public:
  A what () { return {1, 2}; }
};

int main ()
{
  B b {};
  A a {2,3}; // oh no
  return 0;
}

Above example compiles and runs fine, and through the use of braces I can very easily create an A object anywhere.

The only way to prevent this is to write a user constructor, which then cancels out aggregate initialization altogether.

So my question is: is aggregate initialization a "hidden" constructor that is by default public?

Live example: https://onlinegdb.com/r1jHLxzRD

Similar question with no answer: Private aggregate initialization

Upvotes: 5

Views: 556

Answers (3)

HolyBlackCat
HolyBlackCat

Reputation: 96033

Since C++20 this type is no longer an aggregate, so this program no longer compiles.

Manually adding any constructor to a class now prevents it from being an aggregate.

Upvotes: 1

leek
leek

Reputation: 954

You can portably disable aggregate initialization by making the default constructor explicit:

explicit  A () = default;

This works on C++11, C++14, C++17, C++20, and C++23.

Upvotes: 0

eerorika
eerorika

Reputation: 238301

I always thought that aggregate initialization was to save coders from writing custom constructors.

That's something that aggregate initialisation achieves, but defining that as the purpose of aggregate initialisation is overly reductive.

However, this seems to have "sneaked in" a "security by-pass" for private constructors.

This sneaky case of aggregates with private (or even deleted!) default constructor was introduced in C++11 through introduction of defaulted (and deleted) member functions. It no longer exits in C++20 where A is no longer an aggregate.

So my question is: is aggregate initialization a "hidden" constructor

I would describe aggregate initialisation as not using a constructor at all. Instead, members are initialised directly.

Upvotes: 5

Related Questions