Lab 4 Assignment
CT 301 Lab 4
Overview
This is an explore-and-reflect lab. The goal is to learn by trying things, not to finish a polished homework. You will read the lessons and do the quiz questions they include (learncpp shows the solutions), then explore three programs: making a class into a template, giving a class that owns memory a correct deep copy, and adding move. Together the copy constructor, copy assignment, move constructor, and move assignment are the heart of the "rule of five" (you will also hear "rule of seven," which adds swap and a default constructor). When you are done, you record a short video explaining what you tried. There is no written report.
import std;. In this class, and in these labs, we will use #include (for example, #include <iostream>). Both are valid modern C++.Vector<T>), and because it owns a buffer, it must define its own copy constructor, copy assignment, move constructor, and move assignment. Getting those right, a real deep copy and a clean move, is most of the assignment. This lab is the same ideas in miniature.Reading and Quiz
Read these lessons on learncpp.com. Several end with a Quiz time that includes a worked solution; do those and check yourself.
Explore 1: make a class into a template
The Box below holds one int. Turn it into a template so it can hold any type. The main() already tries to use it with an int and a std::string; it will compile once Box is a template.
#include <iostream>
#include <string>
// TODO: make Box a template so it works for ANY type T, not just int.
// (Add template <typename T> above the class, and replace int with T.)
class Box {
public:
Box(int value) : value_(value) {}
int get() const { return value_; }
void set(int value) { value_ = value; }
private:
int value_;
};
int main() {
Box<int> a(42); // these compile only after you templatize Box
Box<std::string> b("hello");
std::cout << a.get() << " " << b.get() << "\n"; // expect: 42 hello
return 0;
}
template <typename T> and replace int with T. Run it (expect 42 hello). Then make a Box<double> and print it too.Explore 2: deep copy
IntArray owns a buffer. As written it has no copy constructor, so the compiler copies the pointer (a shallow copy): the copy and the original share one buffer. Run it first and see a[0] change to 99 when you only meant to change b, and (with -fsanitize=address) a double-free at the end. Then add a deep copy to fix it.
#include <iostream>
class IntArray {
public:
IntArray(int n) : data_(new int[n]), size_(n) {
for (int i = 0; i < n; ++i) data_[i] = 0;
}
~IntArray() { delete[] data_; }
// TODO: add a copy constructor and a copy assignment operator that make a
// DEEP copy (allocate a new buffer and copy the elements), so that two
// IntArrays never share the same buffer.
int& at(int i) { return data_[i]; }
int size() const { return size_; }
private:
int* data_;
int size_;
};
int main() {
IntArray a(3);
a.at(0) = 10; a.at(1) = 20; a.at(2) = 30;
IntArray b = a; // copy; with a DEEP copy, b gets its own buffer
b.at(0) = 99; // this must NOT change a
std::cout << "a[0] = " << a.at(0) << " (should stay 10)" << std::endl;
std::cout << "b[0] = " << b.at(0) << " (should be 99)" << std::endl;
return 0;
}
-fsanitize=address and watch the double-free. Then add a copy constructor and copy assignment that allocate a new buffer and copy the elements. Now a[0] stays 10 and there is no error.Explore 3: move
Copying a big buffer is expensive. A move instead steals the buffer from a temporary or an object you no longer need, leaving the source empty. Add a move constructor and move assignment to your IntArray from Explore 2.
// Add these two to your IntArray from Explore 2.
// Move constructor: take other's buffer, then leave other empty.
IntArray(IntArray&& other) noexcept {
// TODO: copy other's data_ and size_ into this, then set
// other.data_ = nullptr and other.size_ = 0
}
// Move assignment: free what you hold, take other's buffer, leave other empty.
IntArray& operator=(IntArray&& other) noexcept {
// TODO
return *this;
}
Then test it with this main():
#include <utility> // std::move
int main() {
IntArray a(3);
a.at(0) = 10;
IntArray c = std::move(a); // move: c steals a's buffer
std::cout << "after move, a.size() = " << a.size() << " (expect 0)\n";
std::cout << "c[0] = " << c.at(0) << " (expect 10)\n";
return 0;
}
a.size() is 0 (its buffer is gone) and c holds the data. Why is moving cheaper than copying here?Reflect and Record
Record a short video (about 3 to 5 minutes) and upload it to YouTube as Unlisted. In it:
- Show the three programs compiling and running on your screen.
- Explain, in your own words, what made
Boxwork for any type, why a shallow copy was a bug, and what your deep copy and move do differently. - Connect it to Homework 2 (a
Vector<T>that owns a buffer), and mention one thing that surprised you or that you are still unsure about.
This is a reflection, not a presentation. Rough is fine. There is no need to use AI, as you are graded on effort and on showing your own exploration. If you get stuck, you can say so in the video and still get the grade.
Grading
Labs are graded as complete or incomplete.
The labs together are worth 5 percent of your course grade.
How to Submit
Upload your video to YouTube as Unlisted, and submit the link (paste it into the Canvas assignment). Make sure the link is Unlisted, not Private, or we cannot view it. Make sure you do not use your phone. Produce a video with your face and the screen showing what you learned. 5 minutes is more than enough.
Appendix: Online C++ Compilers
Any of the tools below will run the reading examples in your browser, with no local setup. Remember to use #include online, not import std;.
Our course toolchain is GCC 15.2 with -std=c++26. Only Compiler Explorer lets you set that exact combination. The other tools run an older fixed compiler, which is fine for these basic examples.
- In the compiler dropdown, choose x86-64 gcc 15.2.
- In the Compiler options box, type
-std=c++26. - To run the program (not just compile it), open the Execution or Add tool > Executor pane.
- Use the Share button to get a link to your code.
- Select C++ from the language menu.
- Type your code and press Visualize Execution.
- Step forward and back to watch values change.
-std=c++26 here. That is fine for the basic examples.- Set the language (top right) to C++.
- Use the settings gear to pick the C++ standard.
- Press Run, or Debug to step through the code.
c++26. Fine for the basic examples.- Pick the newest GCC from the compiler list.
- Choose C++26 from the standard menu, or add
-std=c++26to the options. - Press Run, then Share for a link.