Letter to the Editor

Letter to the Editor

By Jonathan Wakely

Overload, 21(113):24, February 2013


Dear Editor,

I really enjoyed Cassio Neri’s article on ‘Complex Logic in the Member Initialiser List’ as it’s a problem I’ve had to deal with several times. I was surprised to learn that Listing 6 was valid, because I didn’t realise callers of that constructor didn’t need access to the private ‘storage’ type to create the default argument at the call site. On reflection I realised the caller doesn’t have to name the type and that access checking in C++ is done on names. I love an Overload article that makes me stop halfway through reading to reach for the compiler and learn something new!

Despite discussing how some C++11 features help solve the problems being discussed, I was surprised to notice the article didn’t mention one of the new C++11 features that I find very useful for solving exactly those sort of problems. The ‘delegating constructors’ feature allows one constructor to invoke a different constructor, in order to avoid duplicating logic in constructor bodies. This feature is useful when one constructor (the delegating constructor) wants to process or munge its arguments somehow and then pass them on to another constructor (the target constructor.) Using delegating constructors allows Cassio’s Listing 6 to be rewritten like so:

class bar : public base {
  struct storage {
    storage(double d) : b(d * d) { }
    double b;
  };
  ...
  bar(double d, foo& r1, foo& r2, storage tmp);
  
public:
  bar(double d, foo& r1, foo& r2);
};

bar::bar(double d, foo& r1, foo& r2)
: bar(d, r1, r2, storage(d))
{ }

bar::bar(double d, foo& r1, foo& r2, storage tmp)
: base(tmp.b),
  x_(cos(tmp.b)), y_(sin(tmp.b)), ...
{ }

In this version of the code the user-accessible constructor doesn’t mention the private ‘storage’ type, which separates the interface meant for users from the implementation details of the complex constructor logic. Additionally, I believe it solves several of the problems mentioned in the article and makes the techniques shown in Listing 7 and Listing 8 unnecessary, and ultimately avoids the need to use a discriminated union for this scenario.

Because the temporary ‘storage’ object is initialized in the member initializer list, not the parameter list, there is no restriction on referring to the function parameters, so ‘storage’ can be constructed with ‘d’ and can have an arbitrarily complex constructor that can do any necessary calculations. Because the delegating constructor doesn’t initialize any base classes (that’s done by the target constructor) the ‘storage’ object is guaranteed to be initialized before the target constructor is invoked so it avoids any problems with order of initialization of base classes.

I think using delegating constructors for this problem is almost the ideal solution. The ‘storage’ constructor allows the complex logic to be placed in a separate function where it can be written more naturally (rather than in a contrived function such as bar::init_base ) and that function is guaranteed to be executed at exactly the right time: after the user calls the (delegating) constructor but before the invocation of the target constructor that actually performs initialization of the base classes and members.

The only downside, which might be why they weren’t considered in the original article, is that delegating constructors were not widely supported until quite recently. Clang has supported them since version 3.0, GCC since 4.7 and MSVC now supports them too as of the November 2012 CTP.

Yours,

Jonathan Wakely

Dear Jonathan,

Thank you for bringing this to our attention. Feel free to write in with any further comments. Cassio tells me Jeff Snyder (who can be found online as je4d) contacted him with similar remarks about delegating constructors.

Frances – Overload editor






Your Privacy

By clicking "Accept Non-Essential Cookies" you agree ACCU can store non-essential cookies on your device and disclose information in accordance with our Privacy Policy and Cookie Policy.

Current Setting: Non-Essential Cookies REJECTED


By clicking "Include Third Party Content" you agree ACCU can forward your IP address to third-party sites (such as YouTube) to enhance the information presented on this site, and that third-party sites may store cookies on your device.

Current Setting: Third Party Content EXCLUDED



Settings can be changed at any time from the Cookie Policy page.