This question asks for a clean way of implementing a static factory method in C++, and this answer describes a clear way to do so. Return Value Optimization would save us from making an unnecesary copy of Object
, thus making this way of creating an Object
as efficient as directly invoking a constructor. The overhead of copying i
to id
inside a private constructor is negligible because it's a small int
.
However, the question and answer don't cover a more complex case when Object
contains an instance variable that is an instance of class Foo
(that requires complex initialization logic) rather than a small primitive type. Suppose I want to construct Foo
using the arguments passed to Object
. A solution using a constructor would look something like:
class Object {
Foo foo;
public:
Object(const FooArg& fooArg) {
// Create foo using fooArg here
foo = ...
}
}
An alternative with a static factory method analogous to the quoted answer would be, as it appears to me:
class Object {
Foo foo;
explicit Object(const Foo& foo_):
foo(foo_)
{
}
public:
static Object FromFooArg(const FooArg& fooArg) {
// Create foo using fooArg here
Foo foo = ...
return Object(foo);
}
}
Here, the overhead of copying foo_
to foo
is no longer necessarily negligible, since Foo
can be an arbitrarily complex class. Moreover, as far as I understand (C++ newbie here so I may be wrong), this code implicitly requires for a copy constructor to be defined for Foo
.
What would be a similarly clean but also efficient way of implementing this pattern in this case?
To anticipate possible questions about why this is relevant, I consider having constructors with logic more complicated than just copying the arguments to be an anti-pattern. I expect the constructor to:
- be guaranteed to work and not throw exceptions,
- and not do heavy calculations under the hood.
Thus, I prefer to put complex initialization logic into static methods. Moreover, this approach provides additional benefits such as overloading by static factory method name even when the input argument types are the same, and the possibility of clearly stating what is being done inside in the name of the method.