Handle Exceptions during instantiation

I have a class that will allocate some memory, open a file, populate a structure, and do some other house keeping.

My current thought is to do something like:

     foo f;  //set 2 flags, one that the memory allocation succeeded, one that there is no open file, so no operations are valid except open()
     if(!f.open("filename")) then do something.
   
     open() would do all the dirty work, and every method in the class, would first check to see if a valid file is open and ready for i/o.  This to avoid things like
         foo f;
         f.fetch(); //or whatever would throw an error

The class will be in a static library or DLL, and will be used by many different programs in the Windows environment; although, I might, in my copious free time, try to port to Linux.  

Am I going at this correctly?

One last question, in the case of a failure to open, I want the calling program to decide what to do with the error.  The failure to open might even be anticipated, with some recovery routine.   On the other hand when a programmer does
        foo f;
        f.fetch();   there is no file open, this is programmer's error.  What is the best way to handle this?  It should always stop execution.  I would rather not have to make every call part of an if statement as in if(!f.fetch())... or if(f.valid())f.fetch();
rickhill11Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Karrtik IyerSoftware ArchitectCommented:
Hi Rick, here are my thoughts :
1) I would think of throwing a a custom exception say FileNotOpen exception from the other member functions when open has not been called before calling other functions of this class. And for these members functions we can define that it may throw FileNotOpen exception so that clients know what exceptions they can expect.
Another option would be to return error code from each member function but then client would need to check the error code after every call to any member function. This is similar to the approach that COM follows returning HR value for every function. Even some windows apis use approach of returning boolean and then use of getlasterror to get the exact error code. But for your requirement exception works well.

2) regarding 2  boolean approach in constructor, I'm not sure if that is needed.
A) boolean for whether memory allocation was successful : If object of my class has been created successfully then it means that memory allocation was successful.
You can always have constructor throw an error if there is any failure during memory allocation. I would ensure that my member variables are smart pointers (either unique or shared based on my need) instead of raw pointers, so that in case of exceptions thrown from constructor the already allocated memory is freed automatically by calling it's destructor since it's a smart pointer.
B) boolean to indicate file is open : you would store a file handle as Class member variable after opening the file, so we can always check on the validity of the file handle instead of needing a boolean to find that out. You can check if file handle is a valid pointer. Initially the file pointer which is class member variable would have been set to nullptr in the member initialization list or constructor before opening the file.
3) you may also want think of thread safety in case your library can be called from different threads of same program and if there could be a shared resource.


Thanks,
Karrtik
evilrixSenior Software Engineer (Avast)Commented:
If your class fails to construct properly you should NOT allow the constructor to finish. You should throw an exception to ensure the user of your class cannot proceed with a class that isn't properly constructed. You absolutely do NOT want to go using bool values to decide if a class is properly constructed or not. This is a path to brittle code that is going to be a nightmare to manage and maintain.

Now, the problem here is that if you are allocating resources these need to be cleaned up. If the constructor fails to finish the destructor is NOT called - EVER!!! There are two ways to do this correctly, although one way is better than the other.

1. Use a http://en.cppreference.com/w/cpp/language/function-try-blockfunction try block
2. Use https://en.wikipedia.org/wiki/Smart_pointersmart pointers.

A function try block allows you to wrap the body of the constructor function in a try/catch, such that if an exception percolates you have a chance to free up any resources. You CANNOT swallow these exceptions and if you fail to re-throw once the try/catch has completed it will automatically re-throw it for you.

myclass::myclass()
// this is a function try block
try
{
   // constructor body
}
catch(std::exception const &)
{
   // clean-up (and report?)
}
catch( ... )
{
   // clean-up
} // <<< automatically re-thrown here

Open in new window


Note that this is NOT the same as having a catch-all try block in the body of your function

myclass::myclass()
{
   // this is NOT a function try block, it is just a try/catch in a function body
   try
   {
   }
   catch(std::exception const &)
   {
   }
   catch( ... )
   {
   }
}

Open in new window


The problem with the try block is that you have to know what did and didn't fail to allocate. The better way to deal with failed allocations is to make use of smart pointers. These make use of the RAII idiom and will automatically clean-up only what was allocated. My article explains the concept and C++11 has both a shared_ptr and unique_ptr that you can make use of. If you are not using C++11 you can find the same smart pointers in Boost.
evilrixSenior Software Engineer (Avast)Commented:
It's work noting that originally the std::fstream classes were designed to throw on failure to open but the standards committee decided not to implement them this way because they would behave differently to how their C counter-parts work. For this reason, the default is for them not to throw; however, you can enable "exceptions" by calling the member function of the same name.

You can argue whether this is good or bad design; however, a stream class failing to open a file on construction is NOT the same as a class failing to fully construct. In this case, silent failure if the file fails to open is possibly a valid design, but if the memory resources cannot be allocated to support the correct behaviour of the class this class should be deemed not constructed properly and should fail by emitting an exception.
Exploring ASP.NET Core: Fundamentals

Learn to build web apps and services, IoT apps, and mobile backends by covering the fundamentals of ASP.NET Core and  exploring the core foundations for app libraries.

evilrixSenior Software Engineer (Avast)Commented:
>> I would think of throwing a a custom exception say FileNotOpen exception

I'm not opposed to this idea, but if you do create a custom exception make sure you base it upon one of the standard C++ exceptions so that you can catch them polymorphically. If you don't understand what that means you probably shouldn't be creating your own exception classes. There are plenty of standard exceptions you could use instead.
rickhill11Author Commented:
Evilrix:

I understand the desire to clean up one's messes, and have always done so.  However, the sense that I get from your remarks is that a programmer's failure to clean up his mess when his program crashes, or ends normally has far reaching consequences for the entire computer.  Is this true?  

Say, in an instance of unintended recursion, a program allocates memory, opens files, creates locks on those files, and does this hundreds or thousands of times until the program crashes.  Does Windows not reclaim those resources in some reasonably elegant way?
evilrixSenior Software Engineer (Avast)Commented:
I'm not quite sure how I gave you that impression, but since you asked: I  don't know I'd go as far as to say the entire computer. Of course, if you fail to clean up properly you could, for example, leave files in an inconsistent state. Depending on what these files are, the consequences may be far reaching.

If a process crashes the OS will clean up after it, but only in the sense that resources are bluntly returned to the system. There is a difference between cleaning up and your application leaving persistent resources in a consistent state. Also, if you error handling isn't robust your application won't necessary crash in the scenario you describe, it could just hang.
rickhill11Author Commented:
Evilrix:

If a process crashes the OS will clean up after it, but only in the sense that resources are bluntly returned to the system.

Understood, this is what Unix does, and I've been in that environment for 30+ years.  For that matter, that is what I would expect any multiuser OS to do.

 There is a difference between cleaning up and your application leaving persistent resources in a consistent state.  

Can you be more specific.  I gather from reading Dr. Google that a persistent resource would have to be specifically created/declared.


Also, if you error handling isn't robust your application won't necessary crash in the scenario you describe, it could just hang.

Depending on the programmer and level of skill, this is what I would expect

Thanks for taking the time.
rickhill11Author Commented:
What happens when a constructor fails?  I'd just do one, but I have no idea how to even set one up.

For instance,
someStruct{
...
};

myClass::myClass()
{
     someStruct myStruct;
}

Assuming that someStruct is incredibly large or whatever, and this constructor fails, what will happen assuming that I do nothing to try to catch the error.

BTW, I get the idea the idea that
 
myClass::myClass()
{
     allocate...
     allocate...
     someStruct myStruct;
}

Might require some cleanup, and a try-catch would be called for.  How would I construct this assuming that I want the program to fail, fail as gracefully as possible, but stop further processing?

BTW, I know enough (which is very little)  about smart pointers to know that I could use them here, and reduce the need for cleanup, but I am trying to understand the implications of and how to handle a class constructor that fails.

Thanks again
evilrixSenior Software Engineer (Avast)Commented:
By persistent resource I mean something like a file or database commit. Anything that lasts beyond the life of your application might be left in an inconsistent state if not cleaned up properly.

>> What happens when a constructor fails?
A constructor is deemed to have failed if it emits an exception (as far as C++ the language is concerned). What happens is quite simple. Nothing happens (apart from the exception stack unwinding until caught). No resources already allocated are released,  hence you should use smart pointers to do this for you.

The failed classes destructor is never called because it was never deemed constructed. It is critical that you either use a function try block or (better) smart pointers to make sure any resources allocated during construction (before the point of failure) are released. As I alluded to before, trying to do this properly in a function try block is hard, since you don't known at what point the constructor failed, so knowing what needs releasing can be tricky unless you have (for example) initialised all resource pointers to a sentinel value (normally Null or nullptr).

By using smart pointers you can forget about all this as they take care of it for you. Read my article (see above comment for link) on smart pointers. It's aimed at those who have never used them, explains exactly what they do and how they work. Also see above comments for contractor examples using function try block.
rickhill11Author Commented:
Evilrix:

Thanks for the explanation!

I think that I've learned that a constructor that fails will, without a doubt, cause the program to exit.  The only question is whether I have some cleanup to do using try-catch or smart pointers.  Is this correct?

Rick
Karrtik IyerSoftware ArchitectCommented:
Hi Rick,
You can use the sample code below to reproduce the constructor exception issue.
I have a class with raw pointers and one with smart pointers, just uncomment one of them and comment other to see the behavior (search for //TODO: Rick in the code). You can put a break point in the destructor of temp class in each of this run and you shall understand the behavior.
Thanks,
Karrtik
#include <iostream>
#include <string>
#include <atlbase.h>
#include <memory>

using namespace std;

class temp{
	int* a;
public:
	temp():a(nullptr){
		a = new int(100);
	}
	~temp(){
		cout <<"Temp destructor called" << endl;
		delete a;
	}
	void Display(){
		cout << *a <<endl;
	}
};
class MyClassWithMemoryLeak{
private:
temp* ptr1;
temp* ptr2;
temp* ptr3;
MyClassWithMemoryLeak():ptr1(nullptr),ptr2(nullptr),ptr3(nullptr){
	throw exception();
	ptr3->Display();
}
};
class MyClassWithSmartPointers{
private:
shared_ptr<temp> ptr1;
unique_ptr<temp> ptr2;
unique_ptr<temp> ptr3;
public:
MyClassWithSmartPointers():ptr1(new temp),ptr2(new temp),ptr3(new temp){
	throw exception();
	ptr3->Display();
}
};
int main()
{
	try{
		//TODO: Rick, please uncomment below line and comment the line after to see the issue when raw pointers are used
		//MyClassWithMemoryLeak* ptrmemleak = new MyClassWithMemoryLeak();
		MyClassWithSmartPointers* ptr = new MyClassWithSmartPointers();
	}
	catch(exception& ex)
	{
		cout << ex.what() << endl;
	}
	
	return 0;
}

Open in new window

evilrixSenior Software Engineer (Avast)Commented:
See my inline comments:

#include <iostream>
#include <string>
#include <atlbase.h>
#include <memory>

using namespace std;

class temp{
	int* a;

   public:
      // RX: So, this isn't unsafe because you are allocating only one resource,
      //     the issue is that if you added another pointer with heap allocation
      //     if the second allocation failed the first (pointer a) will never be
      //     deleted because the destructor is never run. If you were to use
      //     smart pointers for both, the destructor of the smart pointers would
      //     take care of deleting (or not) as necessary.
      temp():a(nullptr){
         a = new int(100);
      }

      ~temp(){
         cout <<"Temp destructor called" << endl;
         delete a;
      }

      void Display(){
         cout << *a <<endl;
      }
};
class MyClassWithMemoryLeak{
   private:
      temp* ptr1;
      temp* ptr2;
      temp* ptr3;

      // RX: none of the pointers are allocated memory, but if they were and an
      //     exception was thrown before the constructor finished you'd have the
      //     potential for a memory leak because the destructor will never be
      //     called.
      MyClassWithMemoryLeak():ptr1(nullptr),ptr2(nullptr),ptr3(nullptr){
         throw exception();
         ptr3->Display();
      }
};

class MyClassWithSmartPointers{
   private:
      shared_ptr<temp> ptr1;
      unique_ptr<temp> ptr2;
      unique_ptr<temp> ptr3;


   public:
      // RX: This is nice and safe, because if the constructor fails the smart
      //     pointer destructors (although the destructor for this class isn't
      //     called any members that have been created up until the exception is
      //     thrown still have their destructors called) will clean up whatever
      //     was allocated to them. This is the only sane and safe way to create
      //     resouces that need to be cleaned up. It should be noted that smart
      //     pointers are only designed to work with new/delete heap allocs!
      MyClassWithSmartPointers():ptr1(new temp),ptr2(new temp),ptr3(new temp){
         throw exception();
         ptr3->Display();
   }
};

int main()
{
	try{
		//TODO: Rick, please uncomment below line and comment the line after to see the issue when raw pointers are used
		//MyClassWithMemoryLeak* ptrmemleak = new MyClassWithMemoryLeak();
		MyClassWithSmartPointers* ptr = new MyClassWithSmartPointers();
	}
	catch(exception& ex)
	{
		cout << ex.what() << endl;
	}
	
	return 0;
}

Open in new window

Karrtik IyerSoftware ArchitectCommented:
BTW, I kept the int pointer in class temp as raw pointer so that Rick can debug and see the destructor of temp called when exception is thrown. Else ideally I would have made the int* in class temp also as a unique pointer. Slight typo in the code above for the class without smart pointers (copy/paste error), I have missed to allocate the memory.
#include <iostream>
#include <string>
#include <atlbase.h>
#include <memory>

using namespace std;

class temp{
	int* a;
public:
	temp():a(nullptr){
		a = new int(100);
	}
	~temp(){
		cout <<"Temp destructor called" << endl;
		delete a;
	}
	void Display(){
		cout << *a <<endl;
	}
};
class MyClassWithMemoryLeak{
private:
temp* ptr1;
temp* ptr2;
temp* ptr3;
MyClassWithMemoryLeak():ptr1(new temp),ptr2(new temp),ptr3(new temp){
	throw exception();
	ptr3->Display();
}
};
class MyClassWithSmartPointers{
private:
shared_ptr<temp> ptr1;
unique_ptr<temp> ptr2;
unique_ptr<temp> ptr3;
public:
MyClassWithSmartPointers():ptr1(new temp),ptr2(new temp),ptr3(new temp){
	throw exception();
	ptr3->Display();
}
};
int main()
{
	try{
		//TODO: Rick, please uncomment below line and comment the line after to see the issue when raw pointers are used
		//MyClassWithMemoryLeak* ptrmemleak = new MyClassWithMemoryLeak();
		MyClassWithSmartPointers* ptr = new MyClassWithSmartPointers();
	}
	catch(exception& ex)
	{
		cout << ex.what() << endl;
	}
	
	return 0;
}

                                          

Open in new window

evilrixSenior Software Engineer (Avast)Commented:
Better examples:

// Bad
class foo
{
   int * a;
   int * b;
   
public:
   foo()
      : a(new int())
      , b(new int()) // if this throws a is never cleaned up
   {
      // because of the line below the destructor is never called,
      // meaning both a and b will leak
      throw std::runtime_error("oops");
   }
   
   ~foo() // not called if foo throws
   {
      delete a;
      delete b;
   }
};

// Dangerous, will probably crash on exception
class foo
{
   int * a;
   int * b;
   
public:
   foo()
   try
      : a(new int()) // if this throws???
      , b(new int()) // this is never intialised
   {
      throw std::runtime_error("oops");
   }
   catch(...)
   {
      if(a) delete a;
      if(b) delete b; // if be was never intialised? Dragons be here!
   }
   
   ~foo() // not called if foo throws
   {
      delete a;
      delete b;
   }
};

// Better, but ugly, duplicates code and error prone
class foo
{
   int * a;
   int * b;
   
public:
   foo()
   try
      : a(nullptr)
      , b(nullptr)
   {
      a = new int();
      b = new int();
      throw std::runtime_error("oops");
   }
   catch(...)
   {
      if(a) delete a; // test and delete - duplication of destructor code, ugh!
      if(b) delete b; // test and delete - duplication of destructor code, ugh!
   }
   
   ~foo() // not called if foo throws
   {
      // you could do the deletion in a single function and call it from both
      // the constructor catch and the destructor to avoid code duplication, but
      // it's still completely unnecessary if you use smart pointers.
      delete a;
      delete b;
   }
};

// This is the only safe way to do things
class foo
{
   std::shared_ptr<int> a;
   std::shared_ptr<int> b;
   
public:
   // See how simple the code is now we're using smart pointers? Each smart
   // pointer will take care of deleting the memory it is allocated when it is
   // destructed. If it is never constructed it is never destructed and so it
   // will only delete memory that was actually allocated. In other words, if a
   // is created but b throws on constructor a is deleted by the smart pointer
   // but since b was never constructed its destructor is never called and so it
   // won't try to delete unallocated memory. It's automagically, exception safe
   // and best of all the code is about as simple as it gets.
   foo()
      : a(new int())
      , b(new int())
   {
      throw std::runtime_error("oops");
   }
};

Open in new window

rickhill11Author Commented:
Evilrix:

Thanks for the example, and it worked mostly as I expected.  I am working in vs2012 VC++, I simply dropped your throw error into a class instantiation routine, and, depending on whether I compiled it in a debug version or a release version, it displayed different a different dialog on the screen, but either way, it halted the program.  However, it didn't  display "oops" anywhere.
evilrixSenior Software Engineer (Avast)Commented:
>> However, it didn't  display "oops" anywhere.

Do you catch and log the error in a try/catch block?

If you don't have a catch handler the destructors are NEVER called. You application will abort (this is the default behaviour), but destructors are never called. If you have code that uses destructors to clean up you MUST have a catch handler. Of course, writing code that can just abort is bad design, even if the issue with destructors doesn't affect you, but it's worth bearing this in mind if you are writing test code.

Also, never (NEVER) throw or allow an exception to percolate from a destructor. If you have an exception already in progress (the stack is currently unwinding) and a destructor throws an exception the default behaviour is just to terminate the program. This is almost never what you want to happen. Put simply, destructors should not fail, ever. If you have to, make them catch and swallow (ideally, logging) any exceptions.

For example:

// Never add code to a destructor that throws. If it's unavoidable
// always wrap it in a try/catch block and swallow the exception
// otherwise your app will crash if this destructor is called as part
// of stack unwinding due to another exception.
foo::~foo()
{
   try
   {
      clean_up_code_that_might_throw();
   }
   catch(std::exception const & e)
   {
      cerr << e.what() << std::endl;
   }
   catch(...)
   {
      cerr << "unknown exception" << std::endl;
   }
}

Open in new window

evilrixSenior Software Engineer (Avast)Commented:
>> Do you catch and log the error in a try/catch block?

As in...

int main()
{
   try
   {
      auto && f = foo(); // this throws on construction
   }
   catch(std::exception const & e)
   {
      std::cerr << e.what() << std::endl;
   }
}

Open in new window

rickhill11Author Commented:
Karrtik and Evilrix:

Under what conditions do I care about the pointers not getting deleted properly.  If the class instantiation fails, the program stops, correct?  When it stops, the OS reclaims the memory.

I get that there may be other things that I want to clean up!  I get that, if some persistent resource, to reuse Evilrix's term, is opened/used/set earlier in the same instantiation, then there might be trouble because the desctuctor won't get called.  To go back to Evilrix's example, why do I care about *a and *b?  What am I not seeing?  Unless *a and *b are simply proxies much bigger and complex things.

Thanks again for trying to retrain an old dude.
evilrixSenior Software Engineer (Avast)Commented:
>> If the class instantiation fails, the program stops, correct?
Incorrect. If you have proper exception handling and you are catching your exceptions (as you should be) then the application doesn't stop and you leak memory. If you don't catch then the application aborts (see my comment, above). This is NOT the behaviour you want because destructors are not called during stack unwinding. This means that persistent resources (open files, data base handles and so on) that rely on destructors to be closed off properly won't be and you'll end up with data inconsistencies.

>> why do I care about *a and *b?
In this simple example, you probably don't... but if you are writing a large scale application that absolutely must not "crash", then of course you do. In the real world, programs don't just crash, right? It's a bit like saying, why do I care about the passengers if a car crashes. They're all dead so they don't care :)

Okay, maybe not quite that extreme, but it's the same principle. You care because it's bad programming not to. Applications that crash are, by and large, considered bad :)

>> Thanks again for trying to retrain an old dude.
De nada, amigo.
rickhill11Author Commented:
So a simple question.  Suppose I have some recovery tool in mind when a particular class fails to instantiate.  How do recover, and continue processing?

I'm under the impression that if I do a try-catch, and don't in the catch portion, throw my own exception, then the original exception is re-thrown.
Karrtik IyerSoftware ArchitectCommented:
Hi Rick (Author),
I generally try to categorize my exceptions in two categories,
1> One in which my program can recover graciously and continue
For this cases, it means the exception is not blocking and the system (OS + your app) is in a stable state to continue with other operations. In this case, you can disable those particular operations in your app that created this exception (may be allow 2-3 retries if this error is something was because this file was opened by someone else). Say you had File Load button, but file load was unsuccessful, then this particular button in the UI can be disabled. There is no generic way of recovery, but it is a case to case basis that we need to handle is what I think.
And while proceeding forward, ensure that by proper exception handling + usage of smart pointers, that even though exceptions were generated in some workflow, it did not result in any memory leaks. And it did not corrupt any common resources that other operations or functionalities in your app requires to operate.
2> Where recovery is not possible and only option left is to shutdown the app and let user try restarting it.
So in case 2, since your program is going to crash, in other words you want the program to crash, memory leaks like *a and *b above do not matter, but say instead of *a, you had a named mutex handle, which this process had acquired and another process is waiting for, and without calling release handle on mutex the process A crashed. The process B shall now get wait abandoned state when it calls wait on this mutex, while if the process A had not crashed, it would get Wait Failed state, so the process B has to be smart enough to understand and handle wait abandoned and treat it as a success scenario. But if process A hand a smart pointer (custom class which we can write for window handles) to mutex, then the crash of A would have ensured that release on acquired mutex is invoked before the crash.
Hope this is helpful.
rickhill11Author Commented:
Karrtik,

Very helpful, and I have done what you mention many times.  

The question that still lingers is can I trap an exception that occurs during instantiation of a class.  I was a professional C programmer for almost 30 years, so I am well aware of work arounds, evaluating stability when a resource isn't available, etc.  What I want to know is if there is a way recover when a class fails, for whatever reason, to instantiate.

For instance:

MyClass::MyClass()
{
     fopen(...    //for whatever reason, this file doesn't open properly
     fputc(... //of course this is going to fail

     OR

     char c[1000000000000000000000000000000]  //I'm guessing that I can put enough 0s to make it fail
}   Let me stipulate ahead of time that it is unlikely that I would do either, and there are ample work arounds for both.  My question is simply, once I foolishly put this code in the instantiator for my class, can I recover from the failure of the class?  I believe that the class never existed, so the destructor won't be called.  I believe that I can do a try-catch, but ultimately the program has to fail as a try-catch that doesn't throw some sort of exception will have the original exception rethrown for it.  I believe that the program is kaput, dead, crashed, etc., but under the right conditions, I can try to bring it down gracefully.  

As I read your and Evilrix's comments, I can't determine if the program is completely dead, or if there is some way to keep it going.  I know that the instantiator can't return a value, so I can't say something like
    if(!MyClass mc)...

but can I say something like
     MyClass mc;
     
     //uh oh, failure detected in creating class mc maybe reported by the try-catch mechanism

     MyClass1 mc1;  //to be used in lieu of MyClass.

I believe that when MyClass fails, it is all over but the crying, OK graceful shutdown, but shutdown nonetheless.  I keep reading the comments, and I keep seeing a sliver of hope for continuation of the program, and if it exists, I'd like the understand the mechanism.

Thanks again for taking the time to help.
evilrixSenior Software Engineer (Avast)Commented:
>> I'm under the impression that if I do a try-catch, and don't in the catch portion, throw my own exception, then the original exception is re-thrown.

If you use a function try block yes; however, if you just use a normal try block then no. I sort of alluded to (but fell short of being specific) this above.

>> The question that still lingers is can I trap an exception that occurs during instantiation of a class.
Yes, like this...

class foo
{
public:
   foo::foo()
   {
      try
      {
         // something that may throw
      }
      catch(...)
      {
         // this is a normal try/catch (not a function try) and so won't auto-rethrow
      }
   }

Open in new window


Note, the difference here is the try/catch is INSIDE the function body, whereas with a function try block the try part IS the function body.

>> What I want to know is if there is a way recover when a class fails, for whatever reason, to instantiate.
As noted, yes; however, it is considered very bad practice because you are effectively allowing an object that hasn't been fully constructed to live. Whilst there are times this may be okay, more often that not this isn't what you want and you'll probably end up with each member function having to perform a whole bunch of validation checks before deciding it is safe to be executed. This makes for hard to maintain code that is very brittle.

class foo
{
   bool constructedOk_;

public:
   foo::foo()
      : constructedOk_(true)
   {
      try
      {
         // something that may throw
      }
      catch(...)
      {
         constructedOk_ = false;
      }

      bool constructedOk() const
      {
         return constructedOk_;
      }
   }
  
   int main()
   {
      auto && f = foo();

      if(f.constructedOk())
      {
         // yay - use it
      }
   }

Open in new window


You're also left with the issue of knowing whether the destructor can safely destruct members since you don't know what was and wasn't correct constructed.

The way to report to the creator of your class would be to have a member function that returns a bool to indicate whether there was an error during construction but you then have to rely on them to check this. In the case of failing to open a file (as in fstream) this is probably okay, since the worse that's going to happen is you can't read from a fail. If; however, you have failed to secure a critical resource (such as memory) the chances are your class is going to be useless if it failed to construct and so in this situation it's better to let the exception percolate and let the creator deal with it.

Does that make sense?

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Karrtik IyerSoftware ArchitectCommented:
Hi Rick (Author),

This (please see code below) is the best possible way I am aware of to find out if the object construction was successful in C++.

Thanks,
karrtik
	bool objectallocationfailed = false;
	MyClassWithSmartPointers* ptrmyclass = nullptr;
	try{
		//TODO: Rick, please uncomment below line and comment the line after to see the issue when raw pointers are used
		//MyClassWithMemoryLeak* ptrmemleak = new MyClassWithMemoryLeak();
		ptrmyclass = new MyClassWithSmartPointers();
	}
	catch(exception& ex)
	{
		if(ptrmyclass == nullptr){
			//TODO: you can do your recovery
			objectallocationfailed = true;
			cout<< "Object was not constructed successfull" << endl;
		}
		cout << ex.what() << endl;
	}
	//The boolean can be avoided as well
	if(objectallocationfailed && (ptrmyclass == nullptr)){
		//TODO:Do recovery
		cout << "Doing recovery" <<endl;

	}

Open in new window

evilrixSenior Software Engineer (Avast)Commented:
>> is the best possible way I am aware of to find out if the object construction was successful in C++.

That does sort of work; however, this requires that the class be constructed on the heap (which isn't always what you want). You also then introduce the additional issue of having to duplicate this code pattern everywhere you want to perform this "test" and also you now have to worry about and manage the lifetime of the actual object being constructed (so, you now have to use yet another smart pointer). Basically, you are creating a mass of additional complexity when C++ already has a proper way of dealing with this (let the exception emit and the caller of the constructor deal with it).

So, in short I sort of agree with the that than this is a viable solution but I wouldn't call it the best solution in terms of what you're looking to do is bad practice. I'd call this more of making the best of a bad job (and I mean this in no way critical of karrtik as he is just offering you a solution to try and find a workaround to your requirement).
evilrixSenior Software Engineer (Avast)Commented:
>> I was a professional C programmer for almost 30 years
Please don't take this the wrong way (honest, I mean no offence - heh), but C++ is not C and to try and replicate the same design patterns in C++ (an object/functional programming language) that you used in C (a procedural programming language) will nearly always work against you. I wrote another article that you might want to read regarding C programmers and C++. Heh.

Should I learn C before learning C++? Answer - NO!

On a more light-hearted note, you might also find this amusing:
The Zen of C++

It is tongue in cheek, but tries to make the point that C++ is a bit of a beast in its own right and that there are many (MANY) ways it can catch you out if you try to work against it (or even with it at times).
Karrtik IyerSoftware ArchitectCommented:
Good comments evilrix, and it's helpful for me as well, so you can be critical. I appreciate it.
Yes my suggested solution does require object on heap.
If you want a object on stack, the option is to go for a specific custom exception derived from std::exception, say ObjectFailedToAllocate exception, and in the catch block of this specific custom exception you can do this recovery. This way you can ensure if you have a larger try block which does more than just creating the object of your class, you are not consuming some other exceptions if you were to do the recovery in catch(..)  or catch(exception)  block.
sarabandeCommented:
some addition to the good comments and solutions already given:

from my experience it is not worth to handle an instantiation error with the goal to recover from that error and proceed with the program. actually, I can't remember any c++ instantiation error which was not due to wrong input data (arguments) or programming errors and therefore would not allow to recover since the memory or stack already most likely was corrupted. instead, in my opinion, a fatal error like a failing memory allocation should throw an exception with the goal to give information as many as possible to locate the wrong code that lead to the exceptional case and orderly terminates the program after this ("sorry. the program has crashed.")

in my opinion, it makes much sense to try to make your constructors robust by checking input arguments. also, a try-catch block from begin to end of functions is a good method to avoid unhandled crashes. for gui  applications where high speed isn't required, it also is good to combine the overall try-catch with some kind of permanent logging which monitors enter and leave of each function (including constructors) which could have the complexity to fail. doing so, enables the top level function which finally handles the fatal error to show an error report which includes the current stack history before failure. that is an excellent means to locate and solve the error as well while testing or at the customer's.

you can use preprocessor macros __FILE__, __LINE__, __FUNCTION__ as arguments to logging functions. often the try catch block also is implemented with macros such that your code still is well readable despite of the error (exception) handling.

ReadFile::ReadFile(const std::string & filename)
{
     FUNC_IN(filename)
     
     std::ifstream file(filename.c_str());  // "file not found" would not throw an exception
     std::string line;
     while (std::getline(file, line))
     {
          myarr.push_back(line);  // myarr is a member of ReadFile
     }
 
     FUNC_OUT(errno)
}

Open in new window


FUNC_IN and FUNC_OUT could be defined like

#define FUNC_IN(info) FuncLog::enter( __FILE__, __LINE__, __FUNCTION__, info); try { 

#define FUNC_OUT(err) } catch (MyExc & e) { FuncLog::excatch(ex, err);  throw; } \
                        catch (...) { FuncLog::excatch(err); throw; } \
                        FuncLog::leave( __FUNCTION__, err)

Open in new window


the logging class would use static members to manage the current stack.

note, for windows projects you need to switch-on the handling of so-called SEH exceptions additionally to c++ exceptions. default ooption is to  handle c++ exceptions only, what means that pointer errors ("access violation") were not included (not caught by catch(...) )

Sara
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.