The following "minimal" example should show the use of rule of 3 (and a half).
#include <algorithm>
#include <iostream>
class C
{
std::string* str;
public:
C()
: str(new std::string("default constructed"))
{
std::cout << "std ctor called" << std::endl;
}
C(std::string* _str)
: str(_str)
{
std::cout << "string ctor called, "
<< "address:" << str << std::endl;
}
// copy ctor: does a hard copy of the string
C(const C& other)
: str(new std::string(*(other.str)))
{
std::cout << "copy ctor called" << std::endl;
}
friend void swap(C& c1, C& c2) {
using std::swap;
swap(c1.str, c2.str);
}
const C& operator=(C src) // rule of 3.5
{
using std::swap;
swap(*this, src);
std::cout << "operator= called" << std::endl;
return *this;
}
C get_new() {
return C(str);
}
void print_address() { std::cout << str << std::endl; }
};
int main()
{
C a, b;
a = b.get_new();
a.print_address();
return 0;
}
Compiled it like this (g++ version: 4.7.1):
g++ -Wall test.cpp -o test
Now, what should happen? I assumed that the line a = b.get_new();
would make a hard copy, i.e. allocate a new string. Reason: The operator=()
takes its argument, as typical in this design pattern, per value, which invokes a copy ctor, which will make a deep copy. What really happened?
std ctor called
std ctor called
string ctor called, address:0x433d0b0
operator= called
0x433d0b0
The copy ctor was never being called, and thus, the copy was soft - both pointers were equal. Why is the copy ctor not being called?