CS247 Lecture 4
This time: Linked List ADT continued. move ctor/assignment operator. Elision. Encapsulation.
Issue: although n is freed, the rest of the Nodes in the list are on the heap, must also be freed.
We will write a dtor, which runs when stack allocated objects go out of scope, and when heap allocated objects are freed.
Complaint: Efficiency
In memory it lookes like the following: (upload pic from lecture)
Here, we’ve copied 2b nodes, then delete the originals immediately.
We can observe that getAlphabet()
is an rvalue. It’s going to be deleted by the next line. No one else will use that memory. We can steal it.
We’ll write a [move constructor] for rvalues, which will be faster. Takes in an rvalue. Called on temporary values
other: is a rvalue, but inside the function, other is an lvalue. One more slight optimization:
other.data
has an address, it’s an lvalue. This invokes the copy ctor for the data string. Even though other.data
will die soon. We’d prefer to run the string move ctor.
std::move is included in <utility>
, it forces an lvalue to be treated as an rvalue. So the move ctor runs.
We still have data sharing :
Compiler provided copy assignmnet operator which does shallow copies of pointers. We have data sharing, since p’s first node is changed to a and points to Node n’s b. (include picture) Data sharing again, leaked Node. We’ll implement our own copy assignment operator.
Attempt #1 :
Need to do some cleanup first when it is a assignment operator. Example of breaking:
(include picture) We start by deleting the rest of the linked list.
To protect against self-assignment, add the following to the beginning of the assignment operator:
other is an lvalue reference, we check if it’s the same thing in the memory location, then return *this
.
We’ll rearrange the copy assignment operator slightly:
new
has the posibility to reject our request for more memory, we’ll then quit the function.
Call new
first so if it fails, we haven’t deleted anything yet.
Working copy assignment operator:
There is some code duplicating between copy ctor and coy assignment operator. Can address this using the copy and swap idiom.
(picture example to include)
Exercise: Check what happens with self-assignment! Finally: Move asisgnment operator, for more efficiency:
(include picture)
Exercise: write this without swapping.
If you don’t define a move ctor/assignment operator but you do define a copy ctor/assignment operator, compiler will use copies in all scenarios.
Rule of Five / Big Five If you write one of the following, should usually write all:
- Destructor
- Move constructor operator
- Move assignment operator
- Copy constructor operator
- Copy assignment operator
Elision:
In g++, std = c++14, neither moe nor copy gets called! This is called elision. In certain cases, compiler can skip calling copy/move ctors, instead writing the objects’ values directly into its final location.
Another example:
Here, {1, 5} is writeen directly into r. Note: Elision is possible, even if it changes program output!
- Not expected to know all possible cases, just that it’s possible.
Disable with the flag —fno -elide -constructors (slow down program thoug)