Programming Tips & Tricks

Home Categories: C# | C++ | General | Other

C++ Tips & Tricks: Implicit Conversions, And How To Prohibit Them With 'explicit'

A class constructor that takes one argument also acts as an implicit conversion operator.
Consider this sample class:
class MyInteger
{
public:
int data;
MyInteger(int x):data(x) {}
};
This class allows you to use the following code:
MyInteger m = 123;
Instead of the usual assignment operator, the one-argument constructor is used to implicitly convert the integer 123 to an object of type MyInteger.
In cases like this, where this assignment makes sense, this is a nice feature, since it expresses what we want the code to do.
But now assume you are writing an array class, or some other container. Propably you will create a constructor that takes as its argument the size you want your container to have, so the relevant part will look something like this:
class MyArray
{
public:
int len;
int* data;
MyArray(int x):len(x), data(new int[len]) {}
~MyArray () { if (data) delete data; }
};
Your intended use for this class will look like the following code:
MyArray a(10);
a.data[0] = 123;
You create the array with a size of ten elements, and then you assign an element some value.

But you can still write this:
a = 123;
And it will compile fine. But it will corrupt the memory allocated for a.data, resulting in a crash when the destructor deletes it.
So in essence, a simple typo (like a=1; instead of a[0] = 1;, assuming the class overloads operator[]), will compile fine, but can lead to serious problems which might only manifest themselves much later in the program.

Fortunately, C++ provides us with an easy way to prevent this from happening, in the form of the 'explicit' keyword, which prevents the constructor to be used for implicit type conversion. We can simply add it to our constructor:
explicit MyArray(int x):len(x), data(new int[len]){}
And now we will get a compiler error at a=123;

So, in essence: only write standard one-argument constructors if you want to allow implicit conversion from the argument type to your class type, and are sure this creates no problems. In all other cases, make your one-argument constructors explicit to prevent bugs resulting from nonsensical or dangerous implicit conversions.