Search code examples
c++privatefriendaggregate-initialization

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


Solution

  • 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.