Assume that for the above, we have a regular constructor and a deep copy constructor. In the above, we use the regular constructor when me write new Node {2, nullptr}
, and also when we make Node n{1, new Node {2, nullptr}};
.
When we pass n
to plusOne
, we make a copy, using the copy constructor. Likewise, when we return n
, we also call the copy constructor. Then, when we are initializing n2 with the return of plusOne(n)
, we again, need to call the copy constructor.
So, in the above code snippet, we have a total of 8 constructor calls, 2 for regular and 6 for copy.
So, we can physically count 8 total uses of constructors. However, if we were to run a program to count this, the value may be smaller. This is because of copy/move elision
. Elision refers to a compiler optimization technique that eliminates unnecessary copying of objects.
To compile a program without this compiler feature, we can:
==****check understanding of this**==
The problem here is that n2 is a stack allocated object, and once we need to delete n3, once we exit main, compiler will attempt to destroy n2 since n3 has a pointer to it. However, since it is a stack allocated object, will lead to undefined behaviour if we try to call destructor on it.
-
Invariant: “next” is either nullptr or a valid pointer to a heap-allocated object
- An invariant is a statement that must hold true upon which our class relies
- Options:
-
trust user (not reliable, kinda of don’t trust them)
-
use c++ to enforce the invariant, example:
-
- Options:
- An invariant is a statement that must hold true upon which our class relies
In a similar way, the Node code above has something that violates its invariant. For stack, you can imagine someone going in and change the order of the stack. Of course it’s possible, but it should not be “possible”. We should only allow the client to push
and pop
from the stack, we should never give them control, hence why we need private
and public
parameters for classes
.
Encapsulation
- Our objects are black boxes, capsules, with hidden implementation details
- The user manipulates the data via provided methods, sort of like an
API
- For
class
, by default, everything is private - For
struct
, by default, everything is public
OK, WE CAN FINALLY USE CLASS KEYWORD
So, now let us jump back to the first chunk of code for this lecture, pasted below for convenience:
Goal: Program creates lists with our Node class
Solution: Creating a wrapper class list that has exclusive access to underlying Node objects
-
The above “wrapper class” is an instance of
inheritance
Solution:
Now, lets look at a function for Node
Problem:
- The user depends on
List
to iterate through theNodes
- We could expose
Node
to allow client to directly iterate, but exposingNode
would break the encapsulation
Solution: Iterator Pattern
- Creates a
class
that manages the access ofNode
, and works basically as an abstraction of a pointer - Iterator class is an abstraction of a pointer
- Let the user talk through the list without exposing the
Node
class