21

I have a CPP class whose constructor does some operations. Some of these operations may fail. I know that constructors do not return anything.

My questions are,

  1. Is it allowed to do some operations other that initializing members in a constructor?

  2. Is it possible to tell the calling function that some operations in constructor has been failed?

  3. Can I make new ClassName() return NULL if some errors occur in constructor?

5
  • 22
    You can throw an exception from within the constructor. It's a completely valid pattern. – Andy Jul 27 '16 at 9:31
  • 1
    You probably should have a look at some of the creational patterns of the GoF. I recommend the factory pattern. – SpaceTrucker Jul 27 '16 at 13:51
  • 2
    A common example of #1 is data validation. IE if you have a class Square, with a constructor that takes one parameter, the length of a side, you want to check if that value is greater than 0. – David says Reinstate Monica Jul 27 '16 at 16:43
  • 1
    For the first question, let me warn you that virtual functions can behave unintuitively in constructors. Same with deconstructors. Beware calling such. – user236808 Jul 27 '16 at 17:50
  • 1
    #3 - Why would you want to return a NULL? One of the benefits of OO is NOT having to check return values. Just catch() the appropriate potential exceptions. – MrWonderful Jul 27 '16 at 20:51
42
  1. Yes, though some coding standards may prohibit it.

  2. Yes. The recommended way is to throw an exception. Alternatively, you can store the error information inside the object and provide methods to access this information.

  3. No.

9
  • 4
    Unless the object is still in valid state even though some part of the constructor arguments did not meet requirements and thus is marked as an error, 2) is really not recommended to do. It is better when an object either exists in a valid state or does not exist at all. – Andy Jul 27 '16 at 11:38
  • @DavidPacker Agreed, see here: stackoverflow.com/questions/77639/… But some coding guidelines prohibit exceptions, which is problematic for constructors. – Sebastian Redl Jul 27 '16 at 11:42
  • Somehow I have already given you an upvote for that answer, Sebastian. Interesting. :D – Andy Jul 27 '16 at 11:59
  • 10
    @ooxi No, it's not. Your overridden new is called to allocate memory, but the call to the constructor is done by the compiler after your operator has returned, which means you don't get to catch the error. That's assuming new is called at all; it isn't for stack-allocated objects, which should be most of them. – Sebastian Redl Jul 27 '16 at 13:17
  • 1
    For #1, RAII is a common example where doing more in the constructor may be required. – Eric Jul 27 '16 at 20:53
21

You could create a static method that performs the calculation and returns either an object in case of success or not case of failure.

Depending on how this construction of the object is done, it might be better to create another object that allows construction of objects in a non static method.

Calling a constructor indirectly is often referred to as a "factory".

This would also allow you to return a null-object, which might be a better solution than returning null.

10
  • Thank you @null! Unfortunately can not accept two answers here :( Otherwise I would have accepted this answer too!! Thanks again! – MayurK Jul 27 '16 at 10:58
  • @MayurK no worries, the accepted answer is not to mark the correct answer, but the one that worked for you. – null Jul 27 '16 at 11:05
  • 3
    @null: In C++, you can't just return NULL. For instance, in int foo() { return NULL you would actually return 0 (zero), an integer object. In std::string foo() { return NULL; } you'd accidentally call std::string::string((const char*)NULL) which is Undefined Behavior (NULL does not point to a \0-terminated string). – MSalters Jul 27 '16 at 13:16
  • 3
    std::optional may be a way away but you could always use boost::optional if you wanted to go that way. – Sean Burton Jul 27 '16 at 14:11
  • 1
    @Vld: In C++, objects aren't restricted to class types. And with generic programming, it's not uncommon to end up with factories for int. E.g. std::allocator<int> is a perfectly sane factory. – MSalters Jul 27 '16 at 22:37
5

@SebastianRedl already gave the simple, direct answers, but some extra explanation might be useful.

TL;DR = there's a style rule to keep constructors simple, there's reasons for it, but those reasons mostly relate to a historic (or simply bad) style of coding. Handling of exceptions in constructors is well defined, and destructors will still be called for fully-constructed local variables and members, which means there shouldn't be any problems in idiomatic C++ code. The style rule persists anyway, but normally that's not a problem - not all initialization has to be in the constructor, and particularly not necessarily that constructor.


It's a common style rule that constructors should do the absolute minimum they can to set up a defined valid state. If your initialization is more complex, it should be handled outside the constructor. If there's no cheap-to-initialize value that your constructor can set up, you should weaken the invarants enforced by your class to add one. For example if allocating storage for your class to manage is too expensive, add a not-allocated-yet null state, because of course having special-case states like null never caused anyone any problems. Ahem.

Although common, certainly in this extreme form it's very far from absolute. In particular, as my sarcasm indicates, I'm in the camp that says weakening invariants is almost always too high a price. However, there are reasons behind the style rule, and there's ways to have both minimal constructors and strong invariants.

The reasons relate to automatic destructor cleanup, particularly in the face of exceptions. Basically, there has to be a well-defined point when the compiler becomes responsible for calling destructors. While you're still in a constructor call, the object isn't necessarily fully constructed, so it's not valid to call the destructor for that object. Therefore, the responsibility for destructing the object only transfers to the compiler when the constructor successfully completes. This is known as RAII (Resource Allocation Is Initialization) which isn't really the best name.

If an exception throw occurs inside the constructor, anything part-constructed needs to be explicitly cleaned up, typically in a try .. catch.

However, components of the object which have already successfully constructed are already the compilers responsibility. This means that in practice, it's not really a big deal. e.g.

classname (args) : base1 (args), member2 (args), member3 (args)
{
}

The body of this constructor is empty. So long as the constructors for base1, member2 and member3 are exception safe, there's nothing to worry about. For example, if the constructor of member2 throws, that constructor is responsible for cleaning itself up. The base base1 was already completely constructed, so its destructor will be automatically called. member3 was never even partially constructed, so doesn't need cleanup.

Even when there's a body, local variables that were fully constructed before the exception was thrown will be automatically destructed, just like any other function. Constructor bodies that juggle raw pointers, or "own" some kind of implicit state (stored elsewhere) - typically meaning a begin/acquire function call must be matched to an end/release call - can cause exception safety problems, but the real problem there is failing to manage a resource properly via a class. For example if you replace raw pointers with unique_ptr in the constructor, the destructor for unique_ptr will be called automatically if needed.

There's still other reasons people give for preferring do-the-minimum constructors. One is simply because the style rule exists, many people assume constructor calls are cheap. One way to have that, yet still have strong invariants, is to have a separate factory/builder class that has the weakened invariants instead, and which sets up the needed initial value using (potentially many) normal member-function calls. Once you have the initial state you need, pass that object as an argument to the constructor for the class with the strong invariants. That can "steal the guts" of the weak-invariants object - move semantics - which is a cheap (and usually noexcept) operation.

And of course you can wrap that in a make_whatever () function, so callers of that function never need to see the weakened-invariants class instance.

10
  • The paragraph where you write "While you're still in a constructor call, the object isn't necessarily fully constructed, so it's not valid to call the destructor for that object. Therefore, the responsibility for destructing the object only transfers to the compiler when the constructor successfully completes" could really use an update concerning delegating constructors. The object is fully constructed when any most-derived constructor finished, and the destructor will be called if an exception occurs inside a delegating constructor. – Ben Voigt Jul 27 '16 at 16:23
  • Thus, the "do-the-minimum" constructor can be private, and the "make_whatever()" function can be another constructor that calls the private one. – Ben Voigt Jul 27 '16 at 16:24
  • This is not the definition of RAII I am familiar with. My understanding of RAII is to intentionally acquire a resource in (and only in) an object's constructor and release it in its destructor. In this way, the object can be used on the stack to automatically manage acquisition and release of the resources it encapsulates. The classic example is a lock that acquires a mutex when constructed and releases it on destruction. – Eric Jul 27 '16 at 20:53
  • 1
    @Eric - Yes, it's absolutely standard practice - a standard practice which is commonly called RAII. It's not just me that stretches the definition - it's even Stroustrup, in some talks. Yes, RAII is about linking linking resource lifecycles to object lifecycles, the mental model being ownership. – Steve314 Jul 28 '16 at 3:07
  • 1
    @Eric - previous replies deleted because they were explained badly. Anyway, objects themselves are resources that can be owned. Everything should have an owner, in a chain right up to the main function or static/global variables. An object allocated using new, isn't owned until you assign that responsibility, but smart pointers own the heap-allocated objects they reference, and containers own their data structures. Owners can choose to delete early, the owners destructor is ultimately responsible. – Steve314 Jul 28 '16 at 5:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.