Below is an erroneous implementation of "The rule of three", which I try to understand.
Debugging the program, I found that the debugger has a problem cleaning up int *k
, which could be resolved either by defining int *k = nullptr
or simply setting it to something reasonable in the copy constructor.
However, I do not understand how the resulting error of the program, an access violation, comes into existence.
I do know, after the copy assignment constructor v1
's int *k
no longer points to a valid memory address.
class Vector2 {
public:
std::string name = "default";
int* k;
Vector2(int s, std::string n) : k(new int[s]), name(n) {
}
Vector2(const Vector2 &other) {
std::cout<< "Copy constructor: " << name << std::endl;
}
~Vector2() {
std::cout << "Deleting: " << name << std::endl;
delete[] k;
}
void swap(Vector2& other) {
using std::swap;
swap(k, other.k);
}
Vector2& operator=(Vector2 other) {
std::cout << "Copy assignment constructor: " << name << std::endl;
swap(other);
return *this;
}
};
int main() {
Vector2 v1 = Vector2(2, "v1");
Vector2 v2 = Vector2(4, "v2");
v1 = v2;
std::cout << &v1 << " " << &v2 << std::endl;
std::cout << &v1.k << " " << &v2.k << std::endl;
return 0;
}
Below is the console output of above's program:
Copy constructor: default
Copy assignment constructor: v1
Deleting: default
0000001B5611FA28 0000001B5611FA78
0000001B5611FA50 0000001B5611FAA0
Deleting: v2
Deleting: v1
16:18:42: The program has unexpectedly finished.
The solution can be derived by laying out the exact sequence of events, e.g.: More print outs and testing, what parameters are called when:
Starting in: v1 = v2;
v2
calls copy constructor with the argument other (whatever other is), in particular: its int* k
does not point to valid memory. For simplicity let's call this new Vector2 v3. The error actually arises within the copy constructor, as v3
is not initialised properly in step 1 .
Step 2 and step 3 are basically "hiding", transferring the error from v3
onto v1
.
The interesting question now is, how is v3
actually generated? Not by the default constructor!