C++ Expects An L-Value For 1st Argumentative Essays

This is a comparison of the programming languages Java and C++.

Design aims[edit]

The differences between the programming languages C++ and Java can be traced to their heritage, as they have different design goals.

C++ language was designed for systems and applications programming (a.k.a., infrastructure programming), extending the procedural programming language C, which was designed for efficient execution. To C, C++ added support for object-oriented programming, exception handling, lifetime-based resource management (RAII), generic programming, template metaprogramming, and the C++ Standard Library which includes generic containers and algorithms (STL), and many other general purpose facilities.

Java is a general-purpose, concurrent, class-based, object-oriented programming language that is designed to minimize implementation dependencies. It relies on a Java virtual machine to be secure and highly portable. It is bundled with an extensive library designed to provide a full abstraction of the underlying platform. Java is a statically typed object-oriented language that uses a syntax similar (but incompatible) to C++. It includes a documentation system called Javadoc.

The different goals in the development of C++ and Java resulted in different principles and design trade-offs between the languages. The differences are as follows:

C++Java
Extends C with object-oriented programming and generic programming. C code can most properly be used.Strongly influenced by C++/C syntax.
Compatible with C source code, except for a few corner cases.Provides the Java Native Interface and recently Java Native Access as a way to directly call C/C++ code.
Write once, compile anywhere (WOCA).Write once, run anywhere/everywhere (WORA/WORE).
Allows procedural programming, functional programming, object-oriented programming, generic programming, and template metaprogramming. Favors a mix of paradigms.Allows procedural programming, functional programming (since Java 8) and generic programming (since Java 5), but strongly encourages the object-orientedprogramming paradigm. Includes support for creating scripting languages.
Runs as native executable machine code for the target instruction set(s).Runs on a virtual machine.
Provides object types and type names. Allows reflection via run-time type information (RTTI).Is reflective, allowing metaprogramming and dynamic code generation at runtime.
Has multiple binary compatibility standards (commonly Microsoft (for MSVC compiler) and Itanium/GNU (for almost all other compilers)).Has one binary compatibility standard, cross-platform for OS and compiler.
Optional automated bounds checking (e.g., the method in and containers).All operations are required to be bound-checked by all compliant distributions of Java. HotSpot can remove bounds checking.
Native unsigned arithmetic support.Native unsigned arithmetic unsupported. Java 8 changes some of this, but aspects are unclear.[1]
Standardized minimum limits for all numerical types, but the actual sizes are implementation-defined. Standardized types are available via the standard library .Standardized limits and sizes of all primitive types on all platforms.
Pointers, references, and pass-by-value are supported for all types (primitive or user-defined).All types (primitive types and reference types) are always passed by value.[2]
Memory management can be done manually via , automatically by scope, or by smart pointers. Supports deterministic destruction of objects. Garbage collection ABI standardized in C++11, though compilers are not required to implement garbage collection.Automatic garbage collection. Supports a non-deterministic finalize() method use of which is not recommended.[3]
Resource management can be done manually or by automatic lifetime-based resource management (RAII).Resource management must generally be done manually, or automatically via finalizers, though this is generally discouraged. Has try-with-resources for automatic scope-based resource management (version 7 onwards).

It can also be done using the internal API but that usage is highly discouraged and will be replaced by a public API in an upcoming Java version.

Supports classes, structs (passive data structure (PDS) types), and unions, and can allocate them on the heap or the stack.Classes are allocated on the heap. Java SE 6 optimizes with escape analysis to allocate some objects on the stack.
Allows explicitly overriding types, and some implicit narrowing conversions (for compatibility with C).Rigid type safety except for widening conversions.
The C++ Standard Library was designed to have a limited scope and functions, but includes language support, diagnostics, general utilities, strings, locales, containers, algorithms, iterators, numerics, input/output, random number generators, regular expression parsing, threading facilities, type traits (for static type introspection) and Standard C Library. The Boost library offers more functions including network I/O.

A rich amount of third-party libraries exist for GUI and other functions like: Adaptive Communication Environment (ACE), Crypto++, various XMPPInstant Messaging (IM) libraries,[4]OpenLDAP, Qt, gtkmm.

The standard library has grown with each release. By version 1.6, the library included support for locales, logging, containers and iterators, algorithms, GUI programming (but not using the system GUI), graphics, multi-threading, networking, platform security, introspection, dynamic class loading, blocking and non-blocking I/O. It provided interfaces or support classes for XML, XSLT, MIDI, database connectivity, naming services (e.g. LDAP), cryptography, security services (e.g. Kerberos), print services, and web services. SWT offered an abstraction for platform-specific GUIs, but was superseded by JavaFX in the latest releases ; allowing for graphics acceleration and CSS-themable UIs. It although doesn't support any kind of "native platform look" support.
Operator overloading for most operators. Preserving meaning (semantics) is highly recommended.Operators are not overridable. The language overrides + and += for the String class.
Single and Multiple inheritance of classes, including virtual inheritance.Single inheritance of classes. Supports multiple inheritance via the Interfaces construct, which is equivalent to a C++ class composed of abstract methods.
Compile-time templates. Allows for Turing complete meta-programming.Generics are used to achieve basic type-parametrization, but they do not translate from source code to byte code due to the use of type erasure by the compiler.
Function pointers, function objects, lambdas (in C++11), and interfaces.Functions references, function objects and lambdas were added in Java 8. Classes (and interfaces, which are classes) can be passed as references as well through
No standard inline documentation mechanism. Third-party software (e.g. Doxygen) exists.Extensive Javadoc documentation standard on all system classes and methods.
keyword for defining immutable variables and member functions that do not change the object. Const-ness is propagated as a means to enforce, at compile-time, correctness of the code with respect to mutability of objects (see const-correctness). provides a version of , equivalent to pointers for objects and for primitive types. Immutability of object members achieved via read-only interfaces and object encapsulation.
Supports the statement.Supports labels with loops and statement blocks. is a reserved keyword but is marked as "unused" in the Java specification.
Source code can be written to be cross-platform (can be compiled for Windows, BSD, Linux, macOS, Solaris, etc., without modification) and written to use platform-specific features. Typically compiled into native machine code, must be recompiled for each target platform.Compiled into byte code for the JVM. Byte code is dependent on the Java platform, but is typically independent of operating system specific features.

Language features[edit]

Syntax[edit]

See also: Java syntax and C++ syntax

  • Java syntax has a context-free grammar that can be parsed by a simple LALR parser. Parsing C++ is more complicated. For example, is a sequence of comparisons if Foo is a variable, but creates an object if Foo is the name of a class template.
  • C++ allows namespace-level constants, variables, and functions. In Java, such entities must belong to some given type, and therefore must be defined inside a type definition, either a class or an interface.
  • In C++, objects are values, while in Java they are not. C++ uses value semantics by default, while Java always uses reference semantics. To opt for reference semantics in C++, either a pointer or a reference can be used.
C++Java
classFoo{// Declares class Foointx=0;// Private Member variable. It will// be initialized to 0, if the// constructor would not set it.// (from C++11)public:Foo():x(0)// Constructor for Foo; initializes{}// x to 0. If the initializer were// omitted, the variable would// be initialized to the value that// has been given at declaration of x.intbar(inti){// Member function bar()return3*i+x;}};
classFoo{// Defines class Fooprivateintx;// Member variable, normally declared// as private to enforce encapsulation// initialized to 0 by defaultpublicFoo(){// Constructor for Foo}// no-arg constructor supplied by defaultpublicintbar(inti){// Member method bar()return3*i+x;}}
Fooa;// declares a to be a Foo object value,// initialized using the default constructor.// Another constructor can be used asFooa(args);// or (C++11):Fooa{args};
Fooa=newFoo();// declares a to be a reference to a new Foo object// initialized using the default constructor// Another constructor can be used asFooa=newFoo(args);
Foob=a;// copies the contents of a to a new Foo object b;// alternative syntax is "Foo b(a)"
// Foo b = a;// would declare b to be reference to the object pointed to by aFoob=a.clone();// copies the contents of the object pointed to by a // to a new Foo object;// sets the reference b to point to this new object;// the Foo class must implement the Cloneable interface// for this code to compile
a.x=5;// modifies the object a
a.x=5;// modifies the object referenced by a
std::cout<<b.x<<std::endl;// outputs 0, because b is// some object other than a
System.out.println(b.x);// outputs 0, because b points to// some object other than a
Foo*c;// declares c to be a pointer to a// Foo object (initially// undefined; could point anywhere)
Fooc;// declares c to be a reference to a Foo// object (initially null if c is a class member;// it is necessary to initialize c before use// if it is a local variable)
c=newFoo;// binds c to point to a new Foo object
c=newFoo();// binds c to reference a new Foo object
Foo&d=*c;// binds d to reference the same object to which c points
Food=c;// binds d to reference the same object as c
c->x=5;// modifies the object referenced by c
c.x=5;// modifies the object referenced by c
a.bar(5);// invokes Foo::bar() for ac->bar(5);// invokes Foo::bar() for *c
a.bar(5);// invokes Foo.bar() for ac.bar(5);// invokes Foo.bar() for c
std::cout<<d.x<<std::endl;// outputs 5, because d references the// same object to which c points
System.out.println(d.x);// outputs 5, because d references the// same object as c
  • In C++, it is possible to declare a pointer or reference to a const object in order to prevent client code from modifying it. Functions and methods can also guarantee that they will not modify the object pointed to by a pointer by using the "const" keyword. This enforces const-correctness.
  • In Java, for the most part, const-correctness must rely on the semantics of the class' interface, i.e., it is not strongly enforced, except for public data members that are labeled .
C++Java
constFoo*a;// it is not possible to modify the object// pointed to by a through a
finalFooa;// a declaration of a "final" reference:// it is possible to modify the object, // but the reference will constantly point // to the first object assigned to it
a=newFoo();// Only in constructor
a.x=5;// LEGAL, the object's members can still be modified // unless explicitly declared final in the declaring class
Foo*constb=newFoo();// a declaration of a "const" pointer
finalFoob=newFoo();// a declaration of a "final" reference
b=newFoo();// ILLEGAL, it is not allowed to re-bind it
b=newFoo();// ILLEGAL, it is not allowed to re-bind it
b->x=5;// LEGAL, the object can still be modified
b.x=5;// LEGAL, the object can still be modified
  • C++ supports statements, which may lead to spaghetti code programming. With the exception of the goto statement (which is very rarely seen in real code and highly discouraged), both Java and C++ have basically the same control flow structures, designed to enforce structured control flow, and relies on break and continue statements to provide some -like functions. Some commenters point out that these labelled flow control statements break the single point-of-exit property of structured programming.[5]
  • C++ provides low-level features which Java lacks. In C++, pointers can be used to manipulate specific memory locations, a task necessary for writing low-level operating system components. Similarly, many C++ compilers support an inline assembler.Assembly language codes can be imported to a C program and vise versa.This makes C language even more faster. In Java, such code must reside in external libraries, and can only be accessed via the Java Native Interface, with a significant overhead for each call.

Semantics[edit]

  • C++ allows default values for arguments of a function/method. Java does not. However, method overloading can be used to obtain similar results in Java but generate redundant stub code.
  • The minimum of code needed to compile for C++ is a function, for Java is a class.
  • C++ allows a range of implicit conversions between native types (including some narrowing conversions), and also allows defining implicit conversions involving user-defined types. In Java, only widening conversions between native types are implicit; other conversions require explicit cast syntax.
    • A result of this is that although loop conditions (, and the exit condition in ) in Java and C++ both expect a boolean expression, code such as will cause a compile error in Java because there is no implicit narrowing conversion from int to boolean. This is handy if the code was a typo for . Yet current C++ compilers usually generate a warning when such an assignment is performed within a conditional expression. Similarly, standalone comparison statements, e.g. , without a side effect generate a warning.
  • For passing parameters to functions, C++ supports both pass-by-reference and pass-by-value. In Java, primitive parameters are always passed by value. Class types, interface types, and array types are collectively called reference types in Java and are also always passed by value.[6][7][8]
  • Java built-in types are of a specified size and range defined by the language specification. In C++, a minimal range of values is defined for built-in types, but the exact representation (number of bits) can be mapped to whatever native types are preferred on a given platform.
    • For instance, Java characters are 16-bit Unicode characters, and strings are composed of a sequence of such characters. C++ offers both narrow and wide characters, but the actual size of each is platform dependent, as is the character set used. Strings can be formed from either type.
    • This also implies that C++ compilers can automatically select the most efficient representation for the target platform (i.e., 64-bit integers for a 64-bit platform), while the representation is fixed in Java, meaning the values can either be stored in the less-efficient size, or must pad the remaining bits and add code to emulate the reduced-width behavior.
  • The rounding and precision of floating point values and operations in C++ is implementation-defined (although only very exotic or old platforms depart from the IEEE 754 standard). Java provides an optional strict floating-point model (strictfp) that guarantees more consistent results across platforms, though at the cost of possibly slower run-time performance. However, Java does not comply strictly with the IEEE 754 standard. Most C++ compilers will, by default, comply partly with IEEE 754 (usually excluding strict rounding rules and raise exceptions on NaN results), but provide compliance options of varied strictness, to allow for some optimizing.[9][10] If we label those options from least compliant to most compliant as fast, consistent (Java's strictfp), near-IEEE, and strict-IEEE, we can say that most C++ implementations default to near-IEEE, with options to switch to fast or strict-IEEE, while Java defaults to fast with an option to switch to consistent.
  • In C++, pointers can be manipulated directly as memory address values. Java references are pointers to objects.[11] Java references do not allow direct access to memory addresses or allow memory addresses to be manipulated with pointer arithmetic. In C++ one can construct pointers to pointers, pointers to ints and doubles, and pointers to arbitrary memory locations. Java references only access objects, never primitives, other references, or arbitrary memory locations.
  • In C++, pointers can point to functions or member functions (function pointers). The equivalent mechanism in Java uses object or interface references.
  • Via stack-allocated objects, C++ supports scoped resource management, a technique used to automatically manage memory and other system resources that supports deterministic object destruction. While scoped resource management in C++ cannot be guaranteed (even objects with proper destructors can be allocated using and left undeleted) it provides an effective means of resource management. Shared resources can be managed using , along with to break cyclic references. Java supports automatic memory management using garbage collection which can free unreachable objects even in the presence of cyclic references, but other system resources (files, streams, windows, communication ports, threads, etc.) must be explicitly released because garbage collection is not guaranteed to occur immediately after the last object reference is abandoned.
  • C++ features user-defined operator overloading. Operator overloading allows for user-defined types to support operators (arithmetic, comparisons, etc.) like primitive types via user-defined implementations for these operators. It is generally recommended to preserve the semantics of the operators. Java supports no form of operator overloading (although its library uses the addition operator for string concatenation).
  • Java features standard application programming interface (API) support for reflection and dynamic loading of arbitrary new code.
  • C++ supports static and dynamic linking of binaries.
  • Java has generics, which main purpose is to provide type-safe containers. C++ has compile-time templates, which provide more extensive support for generic programming and metaprogramming. Java has annotations, which allow adding arbitrary custom metadata to classes and metaprogramming via an annotation processing tool.
  • Both Java and C++ distinguish between native types (also termed fundamental or built-in types) and user-defined types (also termed compound types). In Java, native types have value semantics only, and compound types have reference semantics only. In C++ all types have value semantics, but a reference can be created to any type, which will allow the object to be manipulated via reference semantics.
  • C++ supports multiple inheritance of arbitrary classes. In Java a class can derive from only one class, but a class can implement multiple interfaces (in other words, it supports multiple inheritance of types, but only single inheritance of implementation).
  • Java explicitly distinguishes between interfaces and classes. In C++, multiple inheritance and pure virtual functions make it possible to define classes that function almost like Java interfaces do, with a few small differences.
  • Java has both language and standard library support for multi-threading. The keyword in Java provides simple and secure mutex locks to support multi-threaded applications. Java also provides robust and complex libraries for more advanced multi-threading synchronizing. Only as of C++11 is there a defined memory model for multi-threading in C++, and library support for creating threads and for many synchronizing primitives. There are also many third-party libraries for this.
  • C++ member functions can be declared as virtual functions, which means the method to be called is determined by the run-time type of the object (a.k.a. dynamic dispatching). By default, methods in C++ are not virtual (i.e., opt-in virtual). In Java, methods are virtual by default, but can be made non-virtual by using the keyword (i.e., opt-out virtual).
  • C++ enumerations are primitive types and support implicit conversion to integer types (but not from integer types). Java enumerations can be and are used like classes. Another way is to make another class that extends ) and may therefore define constructors, fields, and methods as any other class. As of C++11, C++ also supports strongly-typed enumerations which provide more type-safety and explicit specification of the storage type.
  • Unary operators '++' and '--': in C++ "The operand shall be a modifiable lvalue. [skipped] The result is the updated operand; it is an lvalue...",[12] but in Java "the binary numeric promotion mentioned above may include unboxing conversion and value set conversion. If necessary, value set conversion {and/or [...] boxing conversion} is applied to the sum prior to its being stored in the variable.",[13] i.e. in Java, after the initialization "Integer i=2;", "++i;" changes the reference i by assigning new object, while in C++ the object is still the same.

Resource management[edit]

  • Java offers automatic garbage collection, which may be bypassed in specific circumstances via the Real time Java specification. Memory management in C++ is usually done via constructors, destructors, and smart pointers. The C++ standard permits garbage collection, but does not require it. Garbage collection is rarely used in practice.
  • C++ can allocate arbitrary blocks of memory. Java only allocates memory via object instantiation. Arbitrary memory blocks may be allocated in Java as an array of bytes.
  • Java and C++ use different idioms for resource management. Java relies mainly on garbage collection, which can reclaim memory, while C++ relies mainly on the Resource Acquisition Is Initialization (RAII) idiom. This is reflected in several differences between the two languages:
    • In C++ it is common to allocate objects of compound types as local stack-bound variables which are destroyed when they go out of scope. In Java compound types are always allocated on the heap and collected by the garbage collector (except in virtual machines that use escape analysis to convert heap allocations to stack allocations).
    • C++ has destructors, while Java has finalizers. Both are invoked before an object's deallocation, but they differ significantly. A C++ object's destructor must be invoked implicitly (in the case of stack-bound variables) or explicitly to deallocate an object. The destructor executes synchronously just before the point in a program at which an object is deallocated. Synchronous, coordinated uninitializing and deallocating in C++ thus satisfy the RAII idiom. In Java, object deallocation is implicitly handled by the garbage collector. A Java object's finalizer is invoked asynchronously some time after it has been accessed for the last time and before it is deallocated. Very few objects need finalizers. A finalizer is needed by only objects that must guarantee some cleanup of the object state before deallocating, typically releasing resources external to the JVM.
    • With RAII in C++, one type of resource is typically wrapped inside a small class that allocates the resource upon construction and releases the resource upon destruction, and provide access to the resource in between those points. Any class that contain only such RAII objects do not need to define a destructor since the destructors of the RAII objects are called automatically as an object of this class is destroyed. In Java, safe synchronous deallocation of resources can be performed deterministically using the try/catch/finally construct.
    • In C++, it is possible to have a dangling pointer, a stale reference to an object that has already been deallocated. Attempting to use a dangling pointer typically results in program failure. In Java, the garbage collector will not destroy a referenced object.
    • In C++, it is possible to have uninitialized primitive objects. Java enforces default initialization.
    • In C++, it is possible to have an allocated object to which there is no valid reference. Such an unreachable object cannot be destroyed (deallocated), and results in a memory leak. In contrast, in Java an object will not be deallocated by the garbage collector until it becomes unreachable (by the user program). (Weak references are supported, which work with the Java garbage collector to allow for different strengths of reachability.) Garbage collection in Java prevents many memory leaks, but leaks are still possible under some circumstances.[14][15][16]

Libraries[edit]

  • C++ provides cross-platform access to many features typically available in platform-specific libraries. Direct access from Java to native operating system and hardware functions requires the use of the Java Native Interface.

Runtime[edit]

  • Due to its unconstrained expressiveness, low level C++ language features (e.g. unchecked array access, raw pointers, type punning) cannot be reliably checked at compile-time or without overhead at run-time. Related programming errors can lead to low-level buffer overflows and segmentation faults. The Standard Template Library provides higher-level RAII abstractions (like vector, list and map) to help avoid such errors. In Java, low level errors either cannot occur or are detected by the Java virtual machine (JVM) and reported to the application in the form of an exception.
  • The Java language requires specific behavior in the case of an out-of-bounds array access, which generally requires bounds checking of array accesses. This eliminates a possible source of instability but usually at the cost of slowing execution. In some cases, especially since Java 7, compiler analysis can prove a bounds check unneeded and eliminate it. C++ has no required behavior for out-of-bounds access of native arrays, thus requiring no bounds checking for native arrays. C++ standard library collections like std::vector, however, offer optional bounds checking. In summary, Java arrays are "usually safe; slightly constrained; often have overhead" while C++ native arrays "have optional overhead; are slightly unconstrained; are possibly unsafe."

Templates vs. generics[edit]

Both C++ and Java provide facilities for generic programming, templates and generics, respectively. Although they were created to solve similar kinds of problems, and have similar syntax, they are quite different.

C++ TemplatesJava Generics
Classes, functions, aliases[17] and variables[18] can be templated.Classes and methods can be genericized.
Parameters can be variadic, of any type, integral value, character literal, or a class template.Parameters can be any reference type, including boxed primitive types (i.e. Integer, Boolean...).
Separate instantiations of the class or function will be generated for each parameter-set when compiled. For class templates, only the member functions that are used will be instantiated.One version of the class or function is compiled, works for all type parameters (via type-erasure).
Objects of a class template instantiated with different parameters will have different types at run time (i.e., distinct template instantiations are distinct classes).Type parameters are erased when compiled; objects of a class with different type parameters are the same type at run time. It causes a different constructor. Because of this type erasure, it is not possible to overload methods using different instantiations of the generic class.
Implementation of the class or function template must be visible within a translation unit in order to use it. This usually implies having the definitions in the header files or included in the header file. As of C++11, it is possible to use extern templates to separate compiling of some instantiations.Signature of the class or function from a compiled class file is sufficient to use it.
Templates can be specialized—a separate implementation could be provided for a particular template parameter.Generics cannot be specialized.
Template parameters can have default arguments. Pre-C++11, this was allowed only for template classes, not functions.Generic type parameters cannot have default arguments.
Wildcards unsupported. Instead, return types are often available as nested typedefs. (Also, C++11 added keyword , which acts as a wildcard for any type that can be determined at compile time.)Wildcards supported as type parameter.
No direct support for bounding of type parameters, but metaprogramming provides this[19]Supports bounding of type parameters with "extends" and "super" for upper and lower bounds, respectively; allows enforcement of relationships between type parameters.
Allows instantiation of an object with the type of the parameter type.Precludes instantiation of an object with the type of the parameter type (except via reflection).
Type parameter of class template can be used for static methods and variables.Type parameter of generic class cannot be used for static methods and variables.
Static variables unshared between classes and functions of different type parameters.Static variables shared between instances of classes of different type parameters.
Class and function templates do not enforce type relations for type parameters in their declaration. Use of an incorrect type parameter results in compiling failure, often generating an error message within the template code rather than in the user's code that invokes it. Proper use of templated classes and functions is dependent on proper documentation. Metaprogramming provides these features at the cost added effort. There was a proposition to solve this problem in C++11, so-called Concepts, it is planned for the next standard.Generic classes and functions can enforce type relationships for type parameters in their declaration. Use of an incorrect type parameter results in a type error within the code that uses it. Operations on parametrized types in generic code are only allowed in ways that can be guaranteed to be safe by the declaration. This results in greater type safety at the cost of flexibility.
Templates are Turing-complete (see template metaprogramming).Generics are probably not Turing-complete.

Miscellaneous[edit]

  • Java and C++ use different means to divide code into multiple source files. Java uses a package system that dictates the file name and path for all program definitions. Its compiler imports the executable class files. C++ uses a header filesource code inclusion system to share declarations between source files.
  • Compiled Java code files are generally smaller than code files in C++ as Java bytecode is usually more compact than native machine code and Java programs are never statically linked.
  • C++ compiling features an added textual preprocessing phase, while Java does not. Thus some users add a preprocessing phase to their build process for better support of conditional compiling.
  • Java's division and modulus operators are well defined to truncate to zero. C++ (pre-C++11) does not specify whether or not these operators truncate to zero or "truncate to -infinity". -3/2 will always be -1 in Java and C++11, but a C++03 compiler may return either -1 or -2, depending on the platform. C99 defines division in the same fashion as Java and C++11. Both languages guarantee (where a and b are integer types) that for all a and b (b != 0). The C++03 version will sometimes be faster, as it is allowed to pick whichever truncation mode is native to the processor.
  • The sizes of integer types are defined in Java (int is 32-bit, long is 64-bit), while in C++ the size of integers and pointers is compiler and application binary interface (ABI) dependent within given constraints. Thus a Java program will have consistent behavior across platforms, whereas a C++ program may require adapting for some platforms, but may run faster with more natural integer sizes for the local platform.

An example comparing C++ and Java exists in Wikibooks.

Performance[edit]

In addition to running a compiled Java program, computers running Java applications generally must also run the Java virtual machine (JVM), while compiled C++ programs can be run without external applications. Early versions of Java were significantly outperformed by statically compiled languages such as C++. This is because the program statements of these two closely related languages may compile to a few machine instructions with C++, while compiling into several byte codes involving several machine instructions each when interpreted by a JVM. For example:

Java/C++ statementC++ generated code (x86)Java generated byte code
movedx,[ebp+4h]moveax,[ebp+1Ch]incdwordptr[edx+eax*4]
aload_1 iload_2 dup2 iaload iconst_1 iadd iastore

Since performance optimizing is a very complex issue, it is very difficult to quantify the performance difference between C++ and Java in general terms, and most benchmarks are unreliable and biased. Given the very different natures of the languages, definitive qualitative differences are also difficult to draw. In a nutshell, there are inherent inefficiencies and hard limits on optimizing in Java, given that it heavily relies on flexible high-level abstractions, however, the use of a powerful JIT compiler (as in modern JVM implementations) can mitigate some issues. In any case, if the inefficiencies of Java are too great, compiled C or C++ code can be called from Java via the JNI.

Some inefficiencies that are inherent to the Java language include, mainly:

  • All objects are allocated on the heap. For functions using small objects, this can result in performance degradation and heap fragmentation, while stack allocation, in contrast, costs essentially zero. However, modern JIT compilers mitigate this problem to some extent with escape analysis or escape detection to allocate objects on the stack, since Oracle JDK 6.
  • Performance-critical projects like efficient database systems and messaging libraries have had to use internal unofficial APIs like to gain access to manual resource management and be able to do stack allocation ; effectively manipulating pseudo-pointers.
  • Methods are virtual by default (although they can be made final), usually leading to an abuse of virtual methods, adding a level of indirection to every call. This also slightly increases memory use by adding one pointer per object to a virtual table. It also induces a start-up performance penalty, since a JIT compiler must perform added optimizing passes to devirtualize small functions.
  • A lot of run-time casting required even using standard containers induces a performance penalty. However, most of these casts are statically eliminated by the JIT compiler.
  • Safety guarantees come at a run-time cost. For example, the compiler is required to put appropriate range checks in the code. Guarding each array access with a range check is not efficient, so most JIT compilers will try to eliminate them statically or by moving them out of inner loops (although most native compilers for C++ will do the same when range-checks are optionally used).
  • Lack of access to low-level details prevents the developer from improving the program where the compiler is unable to do so.[20]
  • The mandatory use of reference-semantics for all user-defined types in Java can introduce large amounts of superfluous memory indirections (or jumps) (unless elided by the JIT compiler) which can lead to frequent cache misses (a.k.a. cache thrashing). Furthermore, cache-optimization, usually via cache-aware or cache-oblivious data structures and algorithms, can often lead to orders of magnitude improvements in performance as well as avoiding time-complexity degeneracy that is characteristic of many cache-pessimizing algorithms, and is therefore one of the most important forms of optimization; reference-semantics, as mandated in Java, makes such optimizations impossible to realize in practice (by neither the programmer nor the JIT compiler).
  • Garbage collection,[21] as this form of automatic memory management introduces memory overhead.[22]

However, there are a number of benefits to Java's design, some realized, some only theorized:

  • Java garbage collection may have better cache coherence than the usual use of malloc/new for memory allocation. Nevertheless, arguments exist[weasel words] that both allocators equally fragment the heap and neither exhibits better cache locality. However, in C++, allocation of single objects on the heap is rare, and large quantities of single objects are usually allocated in blocks via an STL container and/or with a small object allocator.[23][24]
  • Run-time compiling can potentially use information about the platform on which the code is being executed to improve code more effectively. However, most state-of-the-art native (C, C++, etc.) compilers generate multiple code paths to employ the full computational abilities of the given system.[25] Also, the inverse argument can be made that native compilers can better exploit architecture-specific optimizing and instruction sets than multi-platform JVM distributions.
  • Run-time compiling allows for more aggressive virtual function inlining than is possible for a static compiler, because the JIT compiler has more information about all possible targets of virtual calls, even if they are in different dynamically loaded modules. Currently available JVM implementations have no problem in inlining most of the monomorphic, mostly monomorphic and dimorphic calls, and research is in progress to inline also megamorphic calls, thanks to the recent invoke dynamic enhancements added in Java 7.[26] Inlining can allow for further optimisations like loop vectorisation or loop unrolling, resulting in a huge overall performance increase.
  • In Java, thread synchronizing is built into the language, so the JIT compiler can potentially, via escape analysis, elide locks,[27] significantly improve the performance of naive multi-threaded code. This method was introduced in Sun JDK 6 update 10 and is named biased locking.[28]

Also, some performance problems occur in C++:

  • Allowing pointers to point to any address can make optimizing difficult due to possible interference between pointers that alias each other. However, the introduction of strict-aliasing rules largely solves this problem.[29]
  • Since the code generated from various instantiations of the same class template in C++ is not shared (as with type-erased generics in Java), excessive use of templates may lead to significant increase of the executable code size (code bloat). However, because function templates are aggressively inlined, they can sometimes reduce code size, but more importantly allow for more aggressive static analysis and code optimizing by the compiler, more often making them more efficient than non-templated code. In contrast, Java generics are necessarily less efficient than non-genericized code.
  • Because in a traditional C++ compiler, dynamic linking is performed after code generating and optimizing in C++, function calls spanning different dynamic modules cannot be inlined. However modern C++ compilers like MSVC and Clang+LLVM offer link-time-code-generation options that allow modules to be compiled to intermediate formats which allows inlining at the final link stage.
  • Because thread support is generally provided by libraries in C++, C++ compilers cannot perform thread-related optimizations. However, since multi-threading memory models were introduced in C++11, modern compilers have the needed language features to implement such optimizations. Furthermore, many optimizing compilers, such as the Intel compiler, provide several language extensions and advanced threading facilities for professional multi-threading development.

Official standard and reference of the language[edit]

Language specification[edit]

The C++ language is defined by ISO/IEC 14882, an ISO standard, which is published by the ISO/IEC JTC1/SC22/WG21 committee. The latest, post-standardization draft of C++11 is available as well.[30]

The C++ language evolves via an open steering committee called the C++ Standards Committee. The committee is composed of the creator of C++ Bjarne Stroustrup, the convener Herb Sutter, and other prominent figures, including many representatives of industries and user-groups (i.e., the stake-holders). Being an open committee, anyone is free to join, participate, and contribute proposals for upcoming releases of the standard and technical specifications. The committee now aims to release a new standard every few years, although in the past strict review processes and discussions have meant longer delays between publication of new standards (1998, 2003, and 2011).

The Java language is defined by the Java Language Specification,[31] a book which is published by Oracle.

The Java language continuously evolves via a process called the Java Community Process, and the world's programming community is represented by a group of people and organizations - the Java Community members[32]—which is actively engaged into the enhancement of the language, by sending public requests - the Java Specification Requests - which must pass formal and public reviews before they get integrated into the language.

The lack of a firm standard for Java and the somewhat more volatile nature of its specifications have been a constant source of criticism by stake-holders wanting more stability and conservatism in the addition of new language and library features. In contrast, the C++ committee also receives constant criticism, for the opposite reason, i.e., being too strict and conservative, and taking too long to release new versions.

Trademarks[

The terms lvalue and rvalue are not something one runs into often in C/C++ programming, but when one does, it's usually not immediately clear what they mean. The most common place to run into these terms are in compiler error & warning messages. For example, compiling the following with :

intfoo() {return2;} intmain() { foo() = 2; return0; }

You get:

test.c: In function 'main': test.c:8:5: error: lvalue required as left operand of assignment

True, this code is somewhat perverse and not something you'd write, but the error message mentions lvalue, which is not a term one usually finds in C/C++ tutorials. Another example is compiling this code with :

int& foo() { return2; }

Now the error is:

testcpp.cpp: In function 'int& foo()': testcpp.cpp:5:12: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'

Here again, the error mentions some mysterious rvalue. So what do lvalue and rvalue mean in C and C++? This is what I intend to explore in this article.

A simple definition

This section presents an intentionally simplified definition of lvalues and rvalues. The rest of the article will elaborate on this definition.

An lvalue (locator value) represents an object that occupies some identifiable location in memory (i.e. has an address).

rvalues are defined by exclusion, by saying that every expression is either an lvalue or an rvalue. Therefore, from the above definition of lvalue, an rvalue is an expression that does not represent an object occupying some identifiable location in memory.

Basic examples

The terms as defined above may appear vague, which is why it's important to see some simple examples right away.

Let's assume we have an integer variable defined and assigned to:

An assignment expects an lvalue as its left operand, and is an lvalue, because it is an object with an identifiable memory location. On the other hand, the following are invalid:

4 = var; // ERROR! (var + 1) = 4; // ERROR!

Neither the constant , nor the expression are lvalues (which makes them rvalues). They're not lvalues because both are temporary results of expressions, which don't have an identifiable memory location (i.e. they can just reside in some temporary register for the duration of the computation). Therefore, assigning to them makes no semantic sense - there's nowhere to assign to.

So it should now be clear what the error message in the first code snippet means. returns a temporary value which is an rvalue. Attempting to assign to it is an error, so when seeing the compiler complains that it expected to see an lvalue on the left-hand-side of the assignment statement.

Not all assignments to results of function calls are invalid, however. For example, C++ references make this possible:

int globalvar = 20; int& foo() { return globalvar; } int main() { foo() = 10; return0; }

Here returns a reference, which is an lvalue, so it can be assigned to. Actually, the ability of C++ to return lvalues from functions is important for implementing some overloaded operators. One common example is overloading the brackets operator in classes that implement some kind of lookup access. does this:

std::map<int, float> mymap; mymap[10] = 5.6;

The assignment works because the non-const overload of returns a reference that can be assigned to.

Modifiable lvalues

Initially when lvalues were defined for C, it literally meant "values suitable for left-hand-side of assignment". Later, however, when ISO C added the keyword, this definition had to be refined. After all:

constint a = 10; // 'a' is an lvalue a = 10; // but it can't be assigned!

So a further refinement had to be added. Not all lvalues can be assigned to. Those that can are called modifiable lvalues. Formally, the C99 standard defines modifiable lvalues as:

[...] an lvalue that does not have array type, does not have an incomplete type, does not have a const-qualified type, and if it is a structure or union, does not have any member (including, recursively, any member or element of all contained aggregates or unions) with a const-qualified type.

Conversions between lvalues and rvalues

Generally speaking, language constructs operating on object values require rvalues as arguments. For example, the binary addition operator takes two rvalues as arguments and returns an rvalue:

int a = 1; // a is an lvalueint b = 2; // b is an lvalueint c = a + b; // + needs rvalues, so a and b are converted to rvalues// and an rvalue is returned

As we've seen earlier, and are both lvalues. Therefore, in the third line, they undergo an implicit lvalue-to-rvalue conversion. All lvalues that aren't arrays, functions or of incomplete types can be converted thus to rvalues.

What about the other direction? Can rvalues be converted to lvalues? Of course not! This would violate the very nature of an lvalue according to its definition [1].

This doesn't mean that lvalues can't be produced from rvalues by more explicit means. For example, the unary (dereference) operator takes an rvalue argument but produces an lvalue as a result. Consider this valid code:

int arr[] = {1, 2}; int* p = &arr[0]; *(p + 1) = 10; // OK: p + 1 is an rvalue, but *(p + 1) is an lvalue

Conversely, the unary address-of operator takes an lvalue argument and produces an rvalue:

int var = 10; int* bad_addr = &(var + 1); // ERROR: lvalue required as unary '&' operandint* addr = &var; // OK: var is an lvalue &var = 40; // ERROR: lvalue required as left operand// of assignment

The ampersand plays another role in C++ - it allows to define reference types. These are called "lvalue references". Non-const lvalue references cannot be assigned rvalues, since that would require an invalid rvalue-to-lvalue conversion:

std::string& sref = std::string(); // ERROR: invalid initialization of// non-const reference of type// 'std::string&' from an rvalue of// type 'std::string'

Constant lvalue references can be assigned rvalues. Since they're constant, the value can't be modified through the reference and hence there's no problem of modifying an rvalue. This makes possible the very common C++ idiom of accepting values by constant references into functions, which avoids unnecessary copying and construction of temporary objects.

CV-qualified rvalues

If we read carefully the portion of the C++ standard discussing lvalue-to-rvalue conversions [2], we notice it says:

An lvalue (3.10) of a non-function, non-array type T can be converted to an rvalue. [...] If T is a non-class type, the type of the rvalue is the cv-unqualified version of T. Otherwise, the type of the rvalue is T.

What is this "cv-unqualified" thing? CV-qualifier is a term used to describe const and volatile type qualifiers.

From section 3.9.3:

Each type which is a cv-unqualified complete or incomplete object type or is void (3.9) has three corresponding cv-qualified versions of its type: a const-qualified version, a volatile-qualified version, and a const-volatile-qualified version. [...] The cv-qualified or cv-unqualified versions of a type are distinct types; however, they shall have the same representation and alignment requirements (3.9)

But what has this got to do with rvalues? Well, in C, rvalues never have cv-qualified types. Only lvalues do. In C++, on the other hand, class rvalues can have cv-qualified types, but built-in types (like ) can't. Consider this example:

#include <iostream>classA { public: void foo() const { std::cout << "A::foo() const\n"; } void foo() { std::cout << "A::foo()\n"; } }; A bar() { return A(); } const A cbar() { return A(); } int main() { bar().foo(); // calls foo cbar().foo(); // calls foo const }

The second call in actually calls the method of , because the type returned by is , which is distinct from . This is exactly what's meant by the last sentence in the quote mentioned earlier. Note also that the return value from is an rvalue. So this is an example of a cv-qualified rvalue in action.

Rvalue references (C++11)

Rvalue references and the related concept of move semantics is one of the most powerful new features the C++11 standard introduces to the language. A full discussion of the feature is way beyond the scope of this humble article [3], but I still want to provide a simple example, because I think it's a good place to demonstrate how an understanding of what lvalues and rvalues are aids our ability to reason about non-trivial language concepts.

I've just spent a good part of this article explaining that one of the main differences between lvalues and rvalues is that lvalues can be modified, and rvalues can't. Well, C++11 adds a crucial twist to this distinction, by allowing us to have references to rvalues and thus modify them, in some special circumstances.

As an example, consider a simplistic implementation of a dynamic "integer vector". I'm showing just the relevant methods here:

classIntvec { public: explicit Intvec(size_t num = 0) : m_size(num), m_data(newint[m_size]) { log("constructor"); } ~Intvec() { log("destructor"); if (m_data) { delete[] m_data; m_data = 0; } } Intvec(const Intvec& other) : m_size(other.m_size), m_data(newint[m_size]) { log("copy constructor"); for (size_t i = 0; i < m_size; ++i) m_data[i] = other.m_data[i]; } Intvec& operator=(const Intvec& other) { log("copy assignment operator"); Intvec tmp(other); std::swap(m_size, tmp.m_size); std::swap(m_data, tmp.m_data); return *this; } private: void log(constchar* msg) { cout << "[" << this << "] " << msg << "\n"; } size_t m_size; int* m_data; };

So, we have the usual constructor, destructor, copy constructor and copy assignment operator [4] defined, all using a logging function to let us know when they're actually called.

Let's run some simple code, which copies the contents of into :

Intvec v1(20); Intvec v2; cout << "assigning lvalue...\n"; v2 = v1; cout << "ended assigning lvalue...\n";

What this prints is:

assigning lvalue... [0x28fef8] copy assignment operator [0x28fec8] copy constructor [0x28fec8] destructor ended assigning lvalue...

Makes sense - this faithfully represents what's going on inside . But suppose that we want to assign some rvalue to :

cout << "assigning rvalue...\n"; v2 = Intvec(33); cout << "ended assigning rvalue...\n";

Although here I just assign a freshly constructed vector, it's just a demonstration of a more general case where some temporary rvalue is being built and then assigned to (this can happen for some function returning a vector, for example). What gets printed now is this:

assigning rvalue... [0x28ff08] constructor [0x28fef8] copy assignment operator [0x28fec8] copy constructor [0x28fec8] destructor [0x28ff08] destructor ended assigning rvalue...

Ouch, this looks like a lot of work. In particular, it has one extra pair of constructor/destructor calls to create and then destroy the temporary object. And this is a shame, because inside the copy assignment operator, another temporary copy is being created and destroyed. That's extra work, for nothing.

Well, no more. C++11 gives us rvalue references with which we can implement "move semantics", and in particular a "move assignment operator" [5]. Let's add another to :

Intvec& operator=(Intvec&& other) { log("move assignment operator"); std::swap(m_size, other.m_size); std::swap(m_data, other.m_data); return *this; }

The syntax is the new rvalue reference. It does exactly what it sounds it does - gives us a reference to an rvalue, which is going to be destroyed after the call. We can use this fact to just "steal" the internals of the rvalue - it won't need them anyway! This prints:

assigning rvalue... [0x28ff08] constructor [0x28fef8] move assignment operator [0x28ff08] destructor ended assigning rvalue...

What happens here is that our new move assignment operator is invoked since an rvalue gets assigned to . The constructor and destructor calls are still needed for the temporary object that's created by , but another temporary inside the assignment operator is no longer needed. The operator simply switches the rvalue's internal buffer with its own, arranging it so the rvalue's destructor will release our object's own buffer, which is no longer used. Neat.

I'll just mention once again that this example is only the tip of the iceberg on move semantics and rvalue references. As you can probably guess, it's a complex subject with a lot of special cases and gotchas to consider. My point here was to demonstrate a very interesting application of the difference between lvalues and rvalues in C++. The compiler obviously knows when some entity is an rvalue, and can arrange to invoke the correct constructor at compile time.

Conclusion

One can write a lot of C++ code without being concerned with the issue of rvalues vs. lvalues, dismissing them as weird compiler jargon in certain error messages. However, as this article aimed to show, getting a better grasp of this topic can aid in a deeper understanding of certain C++ code constructs, and make parts of the C++ spec and discussions between language experts more intelligible.

Also, in the new C++ spec this topic becomes even more important, because C++11's introduction of rvalue references and move semantics. To really grok this new feature of the language, a solid understanding of what rvalues and lvalues are becomes crucial.


0 Replies to “C++ Expects An L-Value For 1st Argumentative Essays”

Lascia un Commento

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *