The major difference (that's important here, anyway) between Java and C++ is memory management.
To a first approximation, in Java everything is an object allocated on the heap, and you access those objects via references (although they're more like C++ pointers than C++ references, and sometimes you may well see them called pointers). The exception is primitive types like int, which is why you can't create an ArrayList<int>
. The system manages the lifetimes of objects for you using garbage collection; when nothing holds a reference to an object, it's collected.
C++ offers you more choice. One option is that you can allocate objects on the heap and access those objects via pointers, using the new
keyword. So far, this is exactly the same as Java, which is probably why Java borrowed the use of the new
keyword. The main difference here is that C++ doesn't keep track of the lifetime of those objects; you have to manually use the delete
keyword when you want the object to be destroyed.
Alternatively, you can allocate on the stack, like so:
int main () {
Rectangle rect(5,8);
cout << "area: " << rect.area();
return 0;
}
Note that this does use the constructor! In this case, the memory for that rect object isn't on the heap, it's on the stack. In some ways, it's now more like a primitive type like int; it lives only as long as it's in scope. Some people will use the term "value semantics" to describe things like this. When it drops out of scope, the object is destroyed.
There are some advantages and disadvantages of using the stack compared to the heap. One is that it's a lot faster to allocate memory on the stack than on the heap (allocating memory on the stack is pretty much done by incrementing a single pointer!); another is that the lifetime of a stack object is completely obvious. A disadvantage is that the stack has a relatively small amount of memory available; if you try to allocate too much on the stack, you're at risk of er... overflowing your stack.
One key thing to flag up here that's different in C++ to Java is that in Java, when an object is destroyed is determined by the garbage collector. From the point of view of a program, it's non-deterministic. This isn't the case with C++; objects are destroyed either when they drop out of scope (for stack-allocated objects) or when they're explicitly deleted (for objects on the heap). So this is why it makes sense for C++ to have destructors, because you know when they'll get called.
This is why C++ doesn't have anything like Java's try-with-resources/AutoCloseable (or, for that matter, IDisposable in C#); the destructor takes that role. If, for example, you use a std::ifstream
to read from file, and you create that object on the stack, the file will be closed for you when the ifstream
drops out of scope, and this holds true for any sort of scope; you don't need a special syntax like try-with-resources.
Now, the typical practice in C++ is to use things allocated on the stack (with value semantics) to provide abstractions to help you do memory management. Examples of this include std::vector<> and std::unique_ptr<>. The pattern of using objects with C++ value semantics to manage the lifetime of other resources (like memory, open files, locks on a mutex, etc.) is known as RAII.
So, to boil it down, the difference is that C++ has two different ways of allocating objects that have really different semantics (value/stack and reference/heap). Java (mostly) only has one (reference/heap). And despite them both having a .
operator, the Java .
operator behaves like the C++ ->
operator, in that they access the fields of an object elsewhere via a pointer (C++) or reference (Java). They can actually both blow up in a similar way, if you try to use ->
on a null pointer, or .
on a null Java reference.
The C++ .
operator accesses the fields of values. It does a different thing, which is why it's different.