C++ : Difference between ‘new’ and direct instantiation. Gotcha !

Seems a common question,

CMyClass *pMyClass = new CMyClass();

verses

CMyClass myClass;

Well one obvious difference is you use the ‘->’ operator to access pMyClass but use ‘.’ for myClass. But I guess you already new that. And, of course, you’ll need to remember to delete pMyClass when you finished with it whereas with myClass it is automatically deleted when it goes out of scope. But you probably knew that as well – and I bet forgot it a few times too :) And real anoraks know one gets allocated on the heap and one on the stack but that’s too much information.

What if CMyClass’ constructor required a string ?

CMyClass *pMyClass = new CMyClass( _T(“Yawn!”) );

verses

CMyClass myClass( _T(“Yawn”) );

Again, no difference.

Now for the gotcha. Lets use the class in a real function:

void MyFunction(LPCWSTR wszWideCharString)

{

CMyClass myClass(CW2CT(wszWideCharString));

myClass.DoSomeCleverStuff();
}

[If you are wondering, CW2CT is a macro to convert from wide string to 'T' string]

Suddenly, it appears you cant access any functions or variables in myClass ! WTF !?

myClass.DoSomeCleverFunction() fails to compile as “expression must have class type”.

Have you sussed it yet ? Well, the macro is defined/implemented as a class which has an implicit conversion to an LPCTSTR, but the compiler doesn’t know about this conversion (how _would_ it know) and so the compiler interprets

CMyClass myClass(CW2CT(wszWideCharString))

as, in fact,  a function prototype !

In this instance, you can force the conversion to take place by casting the CW2CT :

CMyClass myClass( (LPCTSTR)CW2CT(wszWideCharString));

Now it works as expected.

So the motto is : when instantiating a class whose constructor has one or more parameters you should avoid using any macros in the constructor unless you can gaurentee their implementation wont confuse the compiler – specifically your own macros are fine but avoid third party ones.

 

 

Leave a Reply