Question

Gotw 80 includes the following example:

  // Example 1
  //
  #include <string>
  using namespace std;

  class A
  {
  public:
    A( const string& s ) { /* ... */ }
    string f() { return "hello, world"; }
  };

  class B : public A
  {
  public:
    B() : A( s = f() ) {}
  private:
    string s;
  };

  int main()
  {
    B b;
  }

The article goes to discuss why the line s = f() is incorrect - due to object lifetimes and order of construction. The article states that at the time, the error wasn't picked up by the compiler.

However, ignoring the problems of order of intialisation and object lifetime, I don't see how s = f() in the parameter list of the constructor can be legal syntactically - it appears to be trying to initialise a member in the parameter list (or perhaps declaring a default value). Can anyone explain what this syntax is trying to do?

Was it helpful?

Solution

Syntactically it's legal... when you have a base class with a constructor that takes arguments you can of course pass any expression as parameter:

strut A {
    A(int) {}
};

struct B : A {
    B() : A( any expression that returns an int ) {}
};

The problem is that when evaluating the expression in the example the object is not even yet a fully constructed A instance, so that code is invalid for two distinct reasons:

  1. Calls a method of A of an non-instance (the constructor didn't start yet): f() call is illegal.
  2. Assigns to a member that hasn't been initialized: s=... is illegal.

OTHER TIPS

It looks like the intention was to call f() and assign the result to B::s. Afterward, the result of that assignment (which is s) would be used as actual parameter when calling the inherited A constructor.

It's syntactically valid. Replace s in that expression with some non-member variable, and g++ accepts it without issue. You might see similar syntax used more often with ordinary function calls instead of constructor calls.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top