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?
 
     
     
     
    