1. Avoid The new Keyword
In Java, objects are instantiated using the
new keyword, so it might be natural to assume that we should use
new in C++ in the same manner:
However, unlike in Java, a C++ variable instantiated with
new is unmanaged, meaning that you must remember to free the memory after use.
This can be done with the
delete keyword. Coming from the Java world, this seems at best inconvenient, and at worst highly error-prone! Why is an extra statement required for the C++ version, when the Java equivalent is so concise?
In C++, there are multiple ways to instantiate an object and the preferred way to do so is directly onto the stack.
When variables are allocated on the stack, they are automatically deleted once they go out of scope. This is very concise, and has great performance characteristics.
const is More Powerful Than Java’s
A common pattern when designing large applications is to make values immutable. This reduces complexity by lowering the number of moving parts an application has.
In Java, we can use the
final keyword to mark a reference as immutable. However, the data that is being pointed to may change. For example:
So to create truly immutable types, Java developers must mark all fields inside of a class as
In C++ we have the
const keyword, which is far more powerful. If an instance is marked as
const, then none of its members may change, even if they are not marked
const in the class definition!
3. Beware of Stack Slicing!
In Java, the semantics of all objects is that they are on the heap (the reality is bit more complicated due to optimizations done by the JVM, but this is a good rudimentary understanding).
C++ is very different, because it allows the user to decide if the object should live on the heap or on the stack. Generally speaking, we should prefer the stack. It gives predictable (and fast!) performance, but it has a big limitation in that the size of each variable must be known at compile-time. This is a big problem when using inheritance.
In this example we have two classes
B is a subclass of
A. Each has a function
what that returns the class name.
Given these definitions, what do you think the following will do?
If you are coming from the Java world, the answer might surprise you! It turns out that when
y is cast to type
A and assigned to
z, it takes the
what method of class
When a stack-variable is assigned to a super-class in C++, it takes the members and method implementations of that super-class. This is because the size of a variable’s value must not exceed the size of its type. For stack-variables, the compiler just “slices” off the extra information of the sub-class.
Quick Aside: value_ptr
We released a new smart-pointer called
value_ptr to make it easier to preserve value-semantics on the heap. See:
4. Overload Your Operators!
Java does not allow you to define custom value-types and operators similar to
boolean. As a result, vector and matrix implementations can be quite cumbersome!
In C++, we can just overload the
This makes vectors usable with
+, just like the built-in primitives.
5. Take Advantage of Compile-time Programming
Java’s generics are incredibly simple, and for the most part are only useful for collection types. C++ templates expand the possibilities of compile-time programming considerably, and are in some ways more akin to Java’s annotations.
Vector2 class from before. If we want to implement a 3-dimensional version in Java, then we need to create a new class:
In C++, we can make this a parameter of the type, and write generic code that handles all sizes only once! Code is generated at compile-time, so the generic code is no less efficient than the hand-written equivalent.
With this generic definition, we can create vectors of any length easily:
Templates can even speed up compilation times! See our comparison below:
6. Use auto!
Java famously lacks a variable type-inference keyword such as
val (Kotlin) or
let (OCaml). This can make Java code quite verbose, particularly when classes like SimpleBeanFactoryAwareAspectInstanceFactory are in the wild!
With C++, the compiler can figure out many types for you, saving you some typing and making code more readable.
7. Be Prepared to Use More Libraries
The JVM, for better or for worse, gives you many platform abstractions out-of-the-box. By comparison, C++ is extremely lean. It lacks built-in support for file-systems, networking and graphics. Instead, C++ developers have to leverage libraries for this functionality.
A good library will also abstract over platform differences, giving a common set of portable functions, just like Java. Neither approach is strictly better. Java developers benefit from a more unified ecosystem, since everyone is using the same underlying APIs. C++ developers are unburdened by functionality that they do not need, but they also have to make more decisions about what to use, and spend more time integrating it. See:
C++ is an unusual language in that it does not yet have a dominant package manager (we’re working on it!). As a result…hackernoon.com
We created Buckaroo to make it easier to integrate C++ libraries. If you would like try it out, the best place to start is the documentation. You can browse the existing packages on Buckaroo.pm or request more over on the wishlist.