Stan’s Signed Snippets

My positive/negative coding experiences

Parenthesis Confusion in C++

I ran into this problem at least once, and I never actually thought about why it worked with or without the parenthesis, and thought that I was just doing something else wrong. But it was only so easy for me because I was doing a relatively small project, and the changes usually didn’t affect any other files. I never really thought why or how it works. But if you’re developing large scale applications or just portions of it, you need to make sure that you use it properly, or it might be a pain to debug it later. For example, as I will explain later, forgetting to add a parenthesis will keep POD class values from being properly initialized in some cases. If you don’t know the properties of POD class initialization, you could be scratching your head when a comparison fails or the compiler throws you a run-time error! If this doesn’t make sense yet, I recommend that you continue reading.

First thing I want to clear up is this post deals with the dilemma when you create objects using the new operator. If you don’t, then there really is no debate. Consider the following example:

Simple declaration example
1
2
3
4
5
6
7
8
struct Stan
{
     int man;
};


Stan s1;
Stan s2();

`

Here, the second initialization is obviously wrong in this context, because the C++ compiler will interpret it as a function definition with no parameters that returns a Stan object This is clear from the syntax. Things are straightforward so far.

So does it matter if you add a parenthesis at the end of a dynamically generated class? It should definitely matter right?

Using the Stan class from the previous example
1
2
Stan *s1 = new Stan;
Stan *s2 = new Stan();

So what’s going on here! s1 and s2 can’t both be correct right? But once you test it out, it might appear that it doesn’t matter at all. In Visual Studio 2008, the compiler doesn’t throw an error or warning at either of these two declarations. But there are some important differences between these two initializations. I will review the differences in accordance with the c++03 revision. For the run down with the c++98 revision, see Philip Taylor’s comment here on a msdn blog.

First let me introduce some terminology. POD means ‘Plain Old Data’. In C++, objects are either POD or non-POD. A POD class can be described as a simple class with little logic. More specifically, to be a POD class, it has to have data members of one of the following data-types: a built-in type(ie int, double), pointer, union, struct, array, or a class with a trivial constructor. The constructor part basically means that if you did not create a default constructor for your class, the C++ compiler will generate the generic constructor for you. A trivial constructor is a constructor that the compiler generates for you. In addition, a POD class cannot have other data types that are non-POD(for example, a string data type is not a POD class because it has a defined constructor). There are many things that would make a class non-POD even if it contains any of the members mentioned above:

  1. User defined constructor
  2. User defined copy constructor
  3. User defined assignment operator
  4. User defined destructor
  5. Non-POD data types such as a string or a non-POD class

Now let’s go through the differences between these two initializations.

1
Stan *s1 = new Stan;</pre>

In this case, s1 is default initialized, which means that all POD data-types will be left uninitialized. In this case, any int will be uninitialized.

1
Stan *s2 = new Stan();

Here s2 will be value initialized, which means that all data members will be initialized. Here, int will be zero-initialized to 0. Looking at the differences between these two initializations(s1 and s2), it’s clear that if you initialize a POD class without parenthesis, you risk having uninitialized data members. Now if you try to access them, you might get a segfault error. This can be a real headache. If you don’t know that leaving out parenthesis can cause an int to be uninitialized, then it will be hard to find the problem.

Let’s consider another class.

1
2
3
4
5
6
struct Stan
{
     int the;
public:
     Stan():the() {};
};

According to C++03, since I have create a non-trivial default constructor, this is a non-POD class now. So it doesn’t matter if I use the parenthesis, or I don’t.

So to sum it up, if you don’t have a POD class, or if you’re not intentionally planning to leave member objects uninitialized, then I would recommend that you always use parenthesis at the end of your class initializations to avoid possible headaches down the road. In reality, you will rarely create POD classes because they are so simple(unless you’re into functional programming?). The only time I imagine you running into this problem is when the parenthesis was accidently forgotten.