C++ constructor questions.

Started by
7 comments, last by MarkS 13 years, 9 months ago
OK, after years of running, I have finally caved in and am teaching myself C++. I feel dirty....

Anyway, I have a question about constructors.

In C, I might do something like this:

typedef struct some_struct{int *some_ptr;};some_struct *Constructor(int some_params){some_struct *temp;temp = (some_struct *)malloc(sizeof(some_struct));if(temp == NULL)return(NULL);temp->some_ptr = (int *)malloc(some_params * sizeof(int));if(temp->some_ptr == NULL){free(temp);return(NULL);}return(temp);}


As you can see, not only am I allocating an instance of some_struct, but I am also allocating some of the pointers inside some_struct. If there is a memory error, I return NULL and this is checked by the function calling the constructor.

How would this be done in C++? I know that I am basically changing the struct to a class and memory for the class is allocated by new outside of the constructor. At what point is the constructor function called during a call to new? If there are errors allocating memory for pointers in the class, is it possible to free the memory held by the allocated class from within the constructor? What is the exact purpose of a C++ constructor function?

No, I am not a professional programmer. I'm just a hobbyist having fun...

Advertisement
Quote:Original post by maspeir
How would this be done in C++? I know that I am basically changing the struct to a class and memory for the class is allocated by new outside of the constructor. At what point is the constructor function called during a call to new? If there are errors allocating memory for pointers in the class, is it possible to free the memory held by the allocated class from within the constructor? What is the exact purpose of a C++ constructor function?


When new fails, by default, it throws std::bad_alloc. If a constructor throws an exception, the compiler deletes any memory allocated for that instance but DOES NOT CALL the destructor.

So if you do:

class a{public:    a(){ i=new int[20]; j=new int[20]; }    ~a(){ delete i; }    int *i,*j;};


if the allocation for j fails, the instance is deleted, but the memory allocated for i is leaked.

Moving from C to C++, one of the most important things to learn about are std::vector and the variety of smart pointers.

class a{public:    a() : i(20),j(20) { }    std::vector<int> i,j;};


Now if j fails, i is deleted because the std::vector i is a fully constructed object at the point at which j throws std::bad_alloc under the vector's hood.

The short answer to your question is throw exceptions from constructors to report failures, but be aware of the above.
The best way is to uses c++ constructs that does not need to be explicitly freed, like using std::vector in your example. Smart pointers are another way of not needing to care about freeing objects (see std::auto_ptr, boost::shared_ptr, boost::scoped_ptr, ...)

// someclass.h#include <vector>class SomeClass {public:    SomeClass(int vector_size);private:    // Best to use dynamic array which takes care of its own resources    std::vector<int> m_some_vector;};// someclass.cpp#include "someclass.h"SomeClass::SomeClass(int vector_size){    // Resize vector to specified size    m_some_vector.resize(vector_size);}


But it is possible to take care of freeing and deleting, it should be used with care.

// someclass.h#include <vector>class SomeClass {public:    SomeClass(int vector_size);    // Have destructor deleting its resources    ~SomeClass();private:    int * m_some_vector;};// someclass.cpp#include "someclass.h"SomeClass::SomeClass(int vector_size) :    // First initialize vector to null    m_some_vector(0){    // Detect any exceptions    try {        // Try allocating        m_some_vector = new int[vector_size];        // Do something else that might go wrong        //...    } catch(...) { // Catch all errors        // If anything went wrong, delete allocated array        // if something goes wrong during array allocation, m_some_vector will        // still be null, and the following line does nothing        delete [] m_some_vector;        // Rethrow exception        throw;    }}~SomeClass::SomeClass(int vector_size) {     // When SomeClass is deallocated, some vector will also be deallocated     delete [] m_some_vector;}


If something is thrown by a constructor the new operator will automatically free memory used by object.
class foo{	public:	foo(){		delete this;	}};foo *f = 0;f = new foo();


I think constructor won't be called if new'ing object fails and f should remain 0.
You can tell object to delete itself, however f won't be 0.

But I think there's workaround:
struct someResource{};class foo{	public:	foo(foo **result){		someResource *s = 0;		s = new someResource();		if(s)			*result = this;		else{			delete this;			*result = 0;			return;		}	}};int main(){	foo		*f = 0,		*result = 0;	f = new foo(&result);	f = result; //sets f to 0 if constructor failed to allocate something, otherwise just does f = f;}
Moved to For Beginners.

Also, ripiz, you should probably learn about exceptions, which are the normal way to indicate failure in a constructor. Also, please don't actually use that code, as it will invoke undefined behavior if foo is ever subclassed.
I forgot to mention I'm a noob. Also I'm not using it, I don't really see a reason to let program continue if user ran out of RAMs, so I better let it crash.
^ Just letting a program crash without attempting to recover or giving the user some kind of feedback to indicate at least in a general sense what's wrong is a terrible way to write a program.
Quote:Original post by mzeo77
The best way is to uses c++ constructs that does not need to be explicitly freed, like using std::vector in your example. Smart pointers are another way of not needing to care about freeing objects (see std::auto_ptr, boost::shared_ptr, boost::scoped_ptr, ...)

This idiom is called Resource Acquisition Is Initialization, or RAII for short. It's a wonderful thing, as it allows to write elegant exception-safe code. You can use it for all kinds of things. All behavior that comes in pairs, basically (create/destroy, open/close, lock/unlock,...).

Thanks for the info, everyone! It is a lot to process. I'm sure I'll be asking more questions shortly.

No, I am not a professional programmer. I'm just a hobbyist having fun...

This topic is closed to new replies.

Advertisement