Java vs C++
Memory Management
- Java: uses virtual machines (JVM) which has built-in garbage collection (managed runtime).
- you freely create new objects, JVM will clean up the objects when they are no longer used.
- you do not need to know where the objects are located in memory; and JVM may move the objects around due to garbage collection.
- C++: no garbage collection.
- you have to manually track the usage of the objects and free the memory.
- you can directly work with memory locations: once an object is allocated in moemory it does not move. You can find the location using address-of operator
&, like&x. - you need to understand and work with pointers.
References and Pointers
C++ references behave differently than Java references.
- Java: references behave similarly to C++ pointers; for example, you can change the object that a Java reference refers to, and you can assign
nullto a Java reference. - C++: think of a C++ reference as an alias — another name for an existing object. Unlike pointers, references cannot (legally) be
null; they always refer to something. (a reference referring tonullis one type ofUndefined Behavior).
Stack vs Heap
- stack: stack pointer move down to create new memory, move up to release. efficient.
- Variables within the function are allocated on the stack — created within a stack frame upon entering the function and destroyed when destroying that stack frame upon exiting the function.
- heap: unlike the stack, the compiler does not need to know how long the storage must stay on the heap; dynamically create and release; takes longer time than stack.
- for an object needs to outlive the scope where it was created, for example by a factory function.
Differences in Java and C++:
- Java:
- primitive on stack:
boolean,char,byte,short,int,long,float,double,void; more efficient. - all objects are created on the heap, using
new. - object references are on the stack.
A a;meansais just a reference, nothing is created yet;A a = new A();will actually create an object on heap.- both stack and heap in Java are managed by JVM, will be auto cleaned up.
- primitive on stack:
- C++:
A a;will allocate memory in stack;A* a = new A();orauto a = std::make_unique<A>();will allocate memory on the heap, andais a pointer to that memory. Raw pointers needs manual calls todelete; smart pointers will free the memory automatically.- can also be created on the heap using C apis like
malloc(). - stack memory will be auto-released as soon as the variable is out of scope, but not for heap (so if they are not freed there's a memory leak).
Objects
- Java:
int iis not an object,Integer iis. - C++:
int iis an object (intitself is atype, which is not an object).
Memory Overhead
- Java:
- 32-bit Java: 8-byte overhead per object.
- 64-bit Java: 16-byte overhead per object.
- C++:
- no garbage collection and cannot use arbitrary objects for synchronization.
- If you have classes with overridden methods, each object has a pointer to its vtable, just like the Java object's reference to its class.
std::unique_ptrhas memory overhead only if you provide it with some non-trivial deleter.std::shared_ptrhas overhead because of it's memory allocation for the control block (which keeps the ref counter and a pointer list to all weak references);std::shared_ptris always a 2 pointer tuple (one to the object, one to the control block).
Early Binding vs Late Binding
- Java: Early binding, know the type during compiling.
- C++: Late binding, do not know the exact type during compiling, but know in run time. Use
virtual.
Reference Semantics vs Value Semantics
- Java: variables have reference semantics.
- C++: variables have value semantics.
Reference Semantics
When you assign an object variable to another variable in Java, you end up with two variables that refer to the same object.
// Java
String a = new String("Foo");
String b = a;
String c = new String("Foo");
assert(a == b); // a and b refer to the same object
assert(a != c); // a and c refer to different objects
assert(a.equals(c)); // a happens to have the same value as c
You can do the same thing in C++, using pointer syntax or reference syntax:
// C++
std::string a = "Foo";
std::string& r = a;
std::string* p = &a;
std::string b = "Foo";
assert(&a == &r); // a and r both refer to an object at the same address
assert(&a == p); // a and p both refer to an object at the same address
assert(&a != &b); // a and b refer to objects at different addresses
assert(a == b); // a happens to have the same value as b
Value Semantics
In Java, when you assign one primitive variable (e.g. int, float, boolean, etc) to another (int a = b), rather than making a new reference, Java simply copies the value of the first variable into the second. Such copying value semantics are what C++ uses for all variables! C++ uses a type's copy constructor or assignment operator (operator=) to assign one value to another, and if you don't provide these methods for your type, C++ will provide a default for each.
Here's an example to help show this fundamental difference between Java and C++:
// Java
Set<String> s1 = new TreeSet<>();
Set<String> s2 = s1;
s1.add("Alice");
assert(s2.contains("Alice")); // True, because s1 and s2 refer to the same Set.
// C++
std::set<std::string> s1;
std::set<std::string> s2 = s1;
s1.insert("Alice");
assert(s2.empty()); // True, because s2 was copied from s1 at construction time.
Pass By Value vs Pass By Reference
- Java: parameters (including object's reference) are always passed by value.
- C++: parameters could be passed by value, pointer or reference.
Type
Unsigned types
- Java does not support unsigned arithmetic.
- C++ does.
Byte
- C/C++:
byteranges from0to255. - Java:
byteis signed:-127to128.
Compare Strings
- C++:
string::operator==()is usingstring::compare()under the hood, so the 2 strings can be compared directly using==. - Java:
==checks if two strings are pointing to the same string, but to compare string content, useequlas().
Classes
Constructors
Constructors in C++ and Java behave very similarly.
- Types:
- Java: constructor.
- C++: constructor, copy constructor, move constructor.
- Default constructor: In both languages, the compiler provides a default constructor if you don't provide one. A default constructor simply creates an "empty" instance of an object.
- Constructor Ordering:
- The order C++ calls constructors is similar to the order Java would call them.
- C++ has a bigger difference between initialization and assignment than Java does — assignment is disallowed for some types (such as const types).
- Unlike Java, the order of construction within a function argument list or other subexpression is unspecified in most cases. Given
run(Foo(a), Bar(b))you can't assumeFoowill be constructed beforeBar! - The rules for variables at namespace scope are complex. Notably, there is no relative ordering between different translation units! By contrast, Java has a well-defined order for initializing static variables, so this difference forms an area of C++ with subtle and potentially significant pitfalls. This is one of the reasons Google Style prohibits non-trivial global variables.
Destructor
- C++: destructors run within the program's flow of control, guaranteed to run.
- The general rule is that destructors are called in the reverse order that the related constructors were called.
- Java: does not have destructors; the closest concept is the
finalize()method, it is triggered during garbage collection, outside of program's flow of constrol, may or may not be called.finalize()is deprecated in JDK 18.
Inheritance
- Java: single rooted hierarchy, inherit from
Object, does not support multiple inheritance. - C++: supports multiple inheritance.
Overloading
- Java: does NOT support operator overloading, only method overloading.
- C++: supports both method overloading and operator overloading.
Portability
- C++: platform dependent, the source must be recompiled for different platforms.
- Java: platform independent, Java code will be compiled to bytecode, which will be used by JVMs. No need to recompile since JVM will handle differences among different platforms.
Functions
- C++: Functions and data may exist external to any class, global and namespace scopes are available.
- Java: All function and data exist within classes; package scope are available.
Return Code
- C++: The integer returned from the
mainfunction is the process exit status, indicating if the code is successful. - Java: Not the return code from
main, insteadSystem.exit(int status)has to be called.
public static void main(String[] args) {
System.exit(1);
}
Actually, Java's main function has to return void, otherwise an error will be thrown:
Error: Main method must return a value of type void in class XXX, please define the main method as:
public static void main(String[] args)
Interacting with native systems
- C++: can direct call native system libraries.
- Java: only through JNI (Java Native Interface) or JNA (Java Native Access) or the new Foreign-Memory Access API / Foreign Linker API.
Filenames
- Java: class name must match filename, e.g
class Amust be stored inA.java. - C++: no such restriction.
C++ in JVM
OpenJDK is implemented in C++ and Java.
From JDK 16, C++14 features can be used in JVM.
Exceptions
Run-time checking: C++ exception specifications are checked at runtime rather than at compile time, so they offer no programmer guarantees that all exceptions have been handled.
Volatile
- Java:
volatiletells the compiler that the value of a variable must never be cached as its value may change outside of the scope of the program itself (by another thread). Used for inter-thread communication. - C/C++:
volatileis needed when developing embedded systems or device drivers, where you need to read or write a memory-mapped hardware device. Only meant for use for hardware access; do not use it for inter-thread communication.