Jump to content
  • Advertisement
Sign in to follow this  
MarkS

C++ constructor questions.

This topic is 2947 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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;
}

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
^ 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.

Share this post


Link to post
Share on other sites
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,...).

Share this post


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

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!