c++named-constructor

Named constructors and temporary lifetime extension


I'm looking for a way to define a "base" constructor, that will initialize values using defaults, and then extend that base into a number of specialized constructors.

The pseudocode of what I want might look like:

class Foo{
private:
    int val;
    /* ... */

public:
    // Base constructor
    Foo(){ /*...*/ }           // This provides basic initialization of members

    // Named constructors
    static Foo fromString(string s){
        Foo f;                 // Call base constructor
        f.val = s.length();    // Customize base object
        return f;              // Return customized object
    }
    static Foo fromInt(int v){
        Foo f;
        f.val = v;
        return f;
    }
}

At first, I thought about extending the lifetime of the temporary f, but the const declaration prevents me from editing its members. So it seems this is out.

Then I tried the "named constructor" approach (which is shown above). However, I had to modify the example to create the object first, then modify it, then return it. This seems to work, but I'm reasonably confident that it is just a coincidence since f is a temporary and goes out of scope at the end of the function.

I've also considered using something like auto_ptrs, but then I'm working with both Foo objects as well as auto_ptrs to Foo, and this makes the rest of the code "care" whether objects are created via the base constructor (in which case it would be an object) or via one of the extended constructors (in which case it would be a pointer).

If it helps, in Python, I would use something like this:

class Foo(object):
    def __init__(self):
        /* Basic initialization */

    @classmethod
    def fromString(cls, s):
        f = Foo() #†
        f.val = len(s)
        return f

Lastly, there are two reasons I want to do it this way:

  1. Code reuse, I would like to move the common initialization out of each of the constructors and into one. I realize I can do this via an init()-type private method called by each constructor, but I just wanted to mention this.
  2. Clarity and resolve ambiguity. Much like the motivation for the named constructor example, parameter types by themselves aren't enough to determine which ctor should be used. Additionally, the fromSomething syntax provides excellent clarity.

Forgive me if there is a simple solution, my work has shifted from c++ to Java/Python for the past few years so I'm a bit rusty.


Solution

  • This is perfectly valid:

    static Foo fromInt(int v){
        Foo f;
        f.val = v;
        return f;
    }
    

    This invokes Foo's copy constructor when you return f(probably the compiler applies return value optimization, so no copies are made). f goes out of scope, but the return value is just a copy of it, so this is totally valid, it's not just "a coincidence" that it's working.

    So if your worries about using the named constructor approach is just that you don't really know if it works, go ahead with it, it works perfectly.