tags:

views:

189

answers:

5

Just a simple question:

if I had a simple vector class:

class Vector
{
public:
  float x;
  float y;
  float z;
};

Doesnt the RAII concept apply here as well? i.e. to provide a constructor to initialize all values to some values (to prevent uninitialized value being used).

EDIT or to provide a constructor that explicitly asks the user to initialize the member variables before the object can be obstantiated.

i.e.

class Vector
{
public:
  float x;
  float y;
  float z;
public:
  Vector( float x_, float y_, float z_ )
    : x( x_ ), y( y_ ), z( z_ )
  { // Code to check pre-condition; }
};

Should RAII be used to help programmer forgetting to initialize the value before it's used, or is that the developer's responsibility?

Or is that the wrong way of looking at RAII?

I intentionally made this example ridiculously simple. My real question was to answer, for example, a composite class such as:

class VectorField
{
public:
  Vector top;
  Vector bottom;
  Vector back;

  // a lot more!
};

As you can see...if I had to write a constructor to initialize every single member, it's quite tedious.

Thoughts?

+5  A: 

The "R" in RAII stands for Resource. Not everything is a resource.

Many classes, such as std::vector, are self-initializing. You don't need to worry about those.

POD types are not self initializing, so it makes sense to initialize them to some useful value.

Mark Ransom
+3  A: 

I wouldn't exactly say RAII applies here. Remember what the letters stand for: resource acquisition is initialization. You have no resources being acquired here, so RAII doesn't apply.

You could provide a default constructor to Vector; that would remove the need for you to explicitly initialize all the members of VectorField. The compiler would insert code to do that for you.

Rob Kennedy
+4  A: 

Since the fields in your Vector class are built-in types, in order to ensure that they are initialized you'll have to do that in a constructor:

class Vector
{
public:
  float x;
  float y;
  float z;

  Vector() : x(0.0), y( 0.0), z( 0.0) {}
};

Now, if your fields were classes that were properly written, they should automatically initialize (and clean up, if necessary) by themselves.

In a way this is similar and related to RAII in that RAII means that resources (memory, handles, whatever) are acquired and cleaned up automatically by the object.

Michael Burr
A: 

If you don't write constructor, the compiler will generate a default constructor for you, and set those values to default (uninitialized values). Provide a default constructor yourself and initialize the values there will be your best way to do this. I don't think it's too complicated to do that. Don't be too lazy :-)

J.W.
If the values are uninitialized, then I don't think it's proper to say that the compiler-generated constructor has "set those values to default." It hasn't set them to anything at all; that's why they're uninitialized.
Rob Kennedy
+3  A: 

You use the RAII pattern when you need to do explicit cleanup, and want that cleanup to occur at the same time as another object is implicitly cleaned up. This can occur for memory allocation/deallocation, critical section entry/exit, database connections, etc. In your example, the "floats" are cleaned up automatically so you don't need to worry about them. However, say you had the following function that you called to obtain vectors:

Vector* getMeAVector() {
    Vector *v = new Vector();
    // do something
    return v;
}

And say it was the caller's responsibility to delete the returned vector. If you called this code the following way:

Vector *v = getMeAVector();
// do some stuff with v
delete v;

You'd have to remember to free the vector. If the "stuff" is a long bit of code, which may throw an exception, or have a bunch of return statements in there, you'd have to free the vector with every exit point. Even if you do it, the person who maintains the code by adding another "return" statement or calling some library that throws an exception may not. Instead, you could write a class like this:

class AutoVector
{
        Vector *v_;
    public:
        AutoVector(Vector *v) : v_(v) {}
        ~AutoVector() { delete v_; }
};

Then, you could obtain the vector like so:

Vector *v = getMeAVector();
AutoVector av(v);
// do lots of complicated stuff including throwing exceptions, multiple returns, etc.

Then you don't have to worry about deleting the vector any more because when av goes out of scope it will be deleted automatically. You can write a little macro to make the "AutoVector av(v)" syntax a little nicer too, if you want.

This is a bit of a contrived example, but if the surrounding code is complicated, or if it can throw exceptions, or someone comes along and adds a "return" statement in the middle, it's nice that the "AutoVector" will free the memory automatically.

You can do the same thing with an "auto" class that enters a critical section in its ctor and exits in its dtor, etc.

Mike Kale