CISC 3142
Programming Paradigms in C++
Aliasing in Java and C++
Aliases in Java
At the reference variable level, Java uses reference semantics, and thus aliases are fairly ubiquitous
primitive types operate with value semantics
special care is taken for classes whose behavior hold be value semantics (e.g. String);
such classes are typically coded to be immutable to aliasing
Here is an example scenario that illustrates a typical aliasing scenario in Java:
Vector v1 = new Vector();
… // populate the vector
Vector v2 = v1;
v1.add(7);
v2.add(3);
Here's the initial state of things after the vector has been populated (through v1):
The reference to the object is now assigned from v1 to v2
Note the alias is of the entire object, i.e., both reference variables are aliasing the full
state of the vector (capacity, size, and reference to the underlying array)
An element (7) is added through v1:
The integrity of the object is maintained through BOTH reference variables, because they are both referencing the same (full) state
of the object
And finally, another element (3) is added through v2
Again, the integrity of the object i maintained because both reference variables are operating on the full state of the same object
Improper Aliasing in C++
C++ permits value-semantics at the class object level
unlike Java , where class objects are only accessed through reference variables, C++ permits the programmer to directly
declare, create, and manipulate the objects themselves
the integrity of an object may be jeopardized if reference semantics are carelessly mixed with value semantics
a primary cause of such errors is the partial aliasing of the state of an object, i.e., when two objects maintain
part of their state independently, but share other posrtions
and this occurs primarily when there are pointer data members for a class
Here is an example scenario that illustrates the consequences of improper aliasing in C++:
Here's the initial state of things after the vector has been populated
v2 is now initialized with the value of v1 using a copy constructor
Note this is an assignment of the object, not a pointer or reference; i.e., value semantics are being used
Assuming the class-designer did not write their own customized copy constructor, the compiler-supplied
default copy constructor is used — the behavior of which is member-wise copy
This mean that a shallow copy (i.e., pointer value only) is performed on the underlying array pointer, rather than a
full memory allocation and copy of the array itself (deep copy)
… and this is the source of the error; an alias has been created, but only on a portion of the state of the vector object
An element (7) is added through v1:
Notice how, while the size data member of the v1 object has been updated, the size of v2
has not
The state of the v2 object is essentially corrupted, in that it doesn't reflect the addition of the element
This is because the two objects are aliasing only a portion of the logical object (namely the underlying array pointer), while maintaining
independent copies of the rest of it (size and capacity)
Another element (3) is added, this time through v2
This emphasizes the nature of the problem — adding an element through v2 overwrites the previously added element
because of the discrepancy between the states of the two object
And finally, another element (8) is added, this time through v1
The shared array, as well as the objects, are now completely corrupted due to the partial aliasing
Maintaining Proper Value Semantics in C++
The above issue can be resolved by ensuring the proper application of value semantics
no partial aliasing can be permitted; this usually requires the programmer to replace several default (i.e., compiler-supplied) functions with
customized functions appropriate to the specific semantics of the class
these functions in particular include the copy constructor and assignment operator
as the default versions of these two functions employ member-wise copying, they manifest reference semantics
(i.e. shallow copying) when operating on pointers
the class-designer's version of these functions must ensure and maintain the full independence of any copied objects
Here is an example scenario that illustrates the proper of objects in C++:
the code is identical to the above example; the difference is that the class-designer has supplied a proper copy constructor that
will preserve the value semantics for the object.
the latter two element additions are omitted as the correctness of the logic is clear after the addition of the first element
vector v1;
…
vector v2 = v1;
v1 += 7;
Here's the initial state of things after the vector has been populated
Same as above
v2 is now initialized with the value of v1 using a copy constructor
Again, this is an assignment of the object, not a pointer or reference; i.e., value semantics should be used
In this scenario, however, the programmer has written their own copy constructor which allocates a new underlying array for the
new object (v2) and copies the values over from the source (v1) object's array.
The two objects, v1 and v2 are copletely independent; there is no aliasing
An element (7) is added through v1:
Everything is fine now, due to the objects being totally independent of each other
Proper Aliasing in C++ — Using Reference Semantics
One can always use reference semantics as well
This is achieved through the use of pointers or references
Other than parameter and return-value transmission, which is accomplished for the most part using references,
reference semantics in C++ is done using pointer
this is for the most part due to reference not be reseatable; i.e., they can't be reassigned
and, unlike Java, reference semantics can be applied to fundamental types (e.g. int, double, etc) as well;
i.e., one can declare pointers (or references) to such types
The thing to remember is to make sure no partial aliasing — in the sense used above — occurs
In the copying scenario above, we used a customized copy constructor to ensure full value semantics; here we are going to use pointers
to ensure full reference semantics and avoid a partial state aliasing situation
Here is a parallel example to the one above, but uses pointers and reference semantics:
Notice the similarity to the Java scenario, the pointers acting in the same capacity as the reference variables