Photo by fireskystudios.com on Unsplash
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 final
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 final
:
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!
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 A
and B
, where 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 A
.
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.
To prevent this, variables can be pointed to instead. A pointer (or reference) always has the same size, regardless of the size of the value being pointed to.
We released a new smart-pointer called value_ptr
to make it easier to preserve value-semantics on the heap. See:
value_ptr — The Missing C++ Smart-pointer_TL;DR_hackernoon.com
Java does not allow you to define custom value-types and operators similar to int
and boolean
. As a result, vector and matrix implementations can be quite cumbersome!
In C++, we can just overload the +
operator:
This makes vectors usable with +
, just like the built-in primitives.
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.
Recall our 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:
Comparing the Compilation Times of C++ Templates and Macros_TL;DR_hackernoon.com
Java famously lacks a variable type-inference keyword such as auto
(C++), var
(C#), 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.
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:
Approaches to C++ Dependency Management, or Why We Built Buckaroo_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.