In today's post, I want to talk about the rule of zero and give an example of how to achieve it.
Since the beginning of C++, you might have heard of different rules about the special member function. Before C++11, we had only three, now, we have five. Whenever we touch one of these special member functions, it affects the remaining ones. Hence the idea is that once we touch one, we have to be explicit about the others. Okay, it is C++, so have to be explicit means that we can do something but don't have to.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
For simplicity reasons, let's ignore potential access functions. We assume that the data stored in
mData might grow. Maybe there is a
resize operation as well.
Adding missing special members... wait, what?
Let's focus on the two parts, the default constructor and the destructor. By providing them, we are obviously no longer following the rule of zero. Even worse. Since we provided a destructor, we lost the move members, which can be crucial for performance since pointers are perfect for being moved. So to get all this back, we have to write the code in A:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
Great, more special members! Or better urg... Let's see how we can improve this situation. Defaulting the move and copy operations is necessary due to the user-provided destructor. Changing that seems like a good approach.
Reducing the number of user-provided special members
Aside from the rule of zero, you might have heard about no raw pointers or no naked new. How about we follow that idea? Instead of using the raw pointer
int*, we use a
unique_ptr<int>. This simplifies
Stack a lot! We can drop the user-provided destructor and, by that, all the other special members we had to provide.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Knowing that the off-by-one error is a very common error in computer science, we can call it a day, right? One is nearly zero... or not?
You're still hungry for more? Good, because we still have the default constructor left. There is another C++11 feature that comes in handy here, default member initialization.
1 2 3 4 5 6 7 8 9 10
Now we can delete our implementation of the default constructor as well, giving us a class that follows the rule of zero.