Search code examples
c++initializer-listsequence-points

Sequence Point warning in initializer list


I have a Parent class that takes two references that may or may not actually be references to the same thing. In this case when they are the same, I get a sequence point warning in the initializer list of my Child class:

class A
{
  public:
    A(int) {}
  private:
    A() {}
};

class Parent
{
  public:
    Parent(A&, A&) {}
};

class Child : public Parent
{
  public:
    Child() :
      Parent(
          *(_A = new A(0)),
          *(_A)) //Warning on this line
  {
  }

  private:
    A *_A;
};

int main(int argc, char** argv)
{
  return 0;
}

I'm guessing it's because the dereference on that line isn't guaranteed to occur after the memory has been allocated. Regardless, my question is, is there anyway around this without making changes to either Parent or A?


Solution

  • You are right, the order in which the two arguments to the parent constructor are called is not guaranteed (there is no sequence point between them), so the compiler can legally evaluate *(_A) before it evaluates *(_A = new A(0)).

    Do you need to dynamically allocate the A? If not you can do:

    class Child : public Parent
    {
      public:
        Child() : Parent( _a, _a ), _a(0) {}
      private:
        A _a;               // _A is reserved for the implementation (compiler + library)
    };
    

    With one caveat, while it is valid to obtain the address of the member or take a reference into it, it is undefined behavior to use that reference or pointer before the _a member is initialized, which will only happen after Parent constructor completes. That is, as long as Parent's constructor only stores the reference but does not use the object you are safe (riding along the edge of the blade, but no bleeding).

    If Parent constructor uses the reference for anything other than storing it, you can change the Child class to receive a pointer to an already constructed A object:

    Child::Child( A* a ) : Parent( *a, *a ), _a(a) {}