Sunday, April 24, 2011

C++: Is 'this' safe in the constructor?

I've been working hard on something very interesting during the Easter holidays. Wanted to take a quick break, listen to some good music and make a blog post. Alright, my favorite Sony earbuds are on and queued the songs. Now here goes the quick post.

Very often C++ beginners get confused about when and how 'this' pointer can be used. Most common confusion is probably:

Is it safe to use 'this' in the constructor?

Having the confusion, many amateurs avoid using 'this' pointer in constructor. Well, such confusion is harmful for the programmer, project and the company funding the project.

The short answer to the question is: yes, 'this' is very safe in the constructor. All members (or objects) derived (from parent class in case of inheritance) and defined in the class 'will be' allocated and initialized before the constructor gets executed. So you can safely access the members of the class in the constructor.

Now, that was a short answer. For a comprehensive one, we need to discuss in what order objects are created and destroyed and how to use the RAII (Resource Acquisition Is Initialization) idiom. I'll try to make this the topic of my next post.

For a brief discussion on how objects are initialized, you can read this post:
http://kaisar-haque.blogspot.com/2008/06/c-avoid-using-assignments-in.html

Talking about 'this' reminds me of the 'suicidal code'. Six years ago, I have seen the following use of 'this' in a very important server component:

//now commit suicide
delete this;

Needless to say that's an architectural disaster. Many of the times we see such disasters in codes of fresh grades. A good way to avoid this is to train your new team mates on idioms like RAII.

Stay tuned for my next post :).

4 comments:

luc said...

delete this can be dangerous, but interestingly, in gui programming, delete this is used very elegantly, specially in the cases of inplace editing controls..

When the inplace control gets destroyed, in the PostNcDestroy virtual override, the control deletes itself. It's a nice technique to keep the code clean in such cases.

But, whenever u use something like "delete this;" you should be aware of its usage regarding why and where and be extra careful.


Now, that I am done with my babling on and on.. here is the real question to u : why does a warning show "this used in basemember initializer list.." or something like that if it is safe like u say?

Mohammad Kaisar Ul Haque said...

Interesting comments about "delete this".

Answer to the warning question: The warning is a pretty valid one and appears when you pass 'this' pointer in the initializer list of a class. It can be both safe and unsafe depending on the use of it. 'this' pointer is not properly initialized until constructor body starts executing. So when 'this' is used to initialize a member using initializer list, the member needs to be careful as it shouldn't use the 'this' pointer to access its other members or function. However, it can safely hold the reference to 'this'.

Example 1: (safe)
=================
class A {
A *p;
public:
A(): p (this) { }
};

In above case, it's safe to keep a reference of 'this', despite the warning.

Example 2: (unsafe)
===================
class A;

class B {
public:
int y;

B(A *a);
};

class A {
public:
B b;
int x;

A();
};

A::A(): b (this), x(10)
{ }

B::B(A *a): y(a->x)
{ }


int main()
{
A a;
cout << "Invalid value of B::y is " << a.b.y << endl;
}

In the above example, one might except value of b.y is 10 but the value is garbage. This is because B's constructor used A ('this') before A's member (x) was initialized. So we cannot make such use of 'this'.

Similarly, the use of 'this' can be both safe and unsafe for inheritance as well.

Please let me know if that answers your question.

luc said...

Thanks, this gives the answer to a nearly decade passing question that hogged my mind... Thnx..

I always saw that warning, but never gave enough thought to how it can back fire.

So thanks for clearing it up

Mohammad Kaisar Ul Haque said...

Great, thanks.. glad to know it helped!