次の「最小限の」例では、3 (半分) のルールの使用を示します。
#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;
}
次のようにコンパイルしました (g++ バージョン: 4.7.1):
g++ -Wall test.cpp -o test
さて、どうすればいいでしょうか?a = b.get_new();
この行がハードコピーを作成する、つまり新しい文字列を割り当てると仮定しました。理由:operator=()
は、この設計パターンで典型的な値ごとに引数を取り、ディープ コピーを作成するコピー ctor を呼び出します。本当に何が起こったのですか?
std ctor called
std ctor called
string ctor called, address:0x433d0b0
operator= called
0x433d0b0
コピー ctor が呼び出されることはなかったため、コピーはソフトでした。つまり、両方のポインターが同じでした。copy ctor が呼び出されないのはなぜですか?