Copy Control and Resource Management
we first have to decide what copying an object of our type will mean. In general, we have two choices: We can define the copy operations to make the class behave like a value or like a pointer.
1、Classes That Act Like Values
(1)、A copy constructor that copies the string, not just the pointer
(2)、A destructor to free the string
(3)、A copy-assignment operator to free the object’s existing string and copy the string from its right-hand operand
The valuelike version of HasPtr is as follow:
class HasPtr {
public:
HasPtr(const std::string &s = std::string()): ps(new std::string(s)), i(0) { }
// each HasPtr has its own copy of the string to which ps points
HasPtr(const HasPtr &p): ps(new std::string(*p.ps)), i(p.i) { }
HasPtr& operator=(const HasPtr &rhs)
{
auto newp = new string(*rhs.ps); // copy the underlying string
delete ps; // free the old memory
ps = newp; // copy data from rhs into this object
i = rhs.i;
return *this; // return this object
}
~HasPtr() { delete ps; }
private:
std::string *ps;
int i;
};
Key Concept: Assignment Operators
There are two points to keep in mind when you write an assignment operator:
(1)、Assignment operators must work correctly if an object is assigned to itself.
(2)、Most assignment operators share work with the destructor and copy constructor
2、Classes That Act Like Pointers
Reference counting works as follows:
(1): In addition to initializing the object, each constructor (other than the copy constructor) creates a counter.This counter will keep track of how many objects share state with the object we are creating. When we create an object, there is only one such object, so we initialize the counter to 1.
(2): The copy constructor does not allocate a new counter; instead, it copies the data members of its given object, including the counter. The copy constructor increments this shared counter, indicating that there is another user of that object’s state.
(3): The destructor decrements the counter, indicating that there is one less user of the shared state. If the count goes to zero, the destructor deletes that state.
(4): The copy-assignment operator increments the right-hand operand’s counter and decrements the counter of the left-hand operand. If the counter for the left-hand operand goes to zero, there are no more users. In this case, the copy-assignment operator must destroy the state of the left-hand operand
#include <string>
class HasPtr {
public:
HasPtr(const std::string& s = std::string())
: ps(new std::string(s)), i(0), use(new size_t(1))
{
}
HasPtr(const HasPtr& hp) : ps(hp.ps), i(hp.i), use(hp.use) { ++*use; }
HasPtr& operator=(const HasPtr& rhs)
{
++*rhs.use;
if (--*use == 0) {
delete ps;
delete use;
}
ps = rhs.ps;
i = rhs.i;
use = rhs.use;
return *this;
}
~HasPtr()
{
if (--*use == 0) {
delete ps;
delete use;
}
}
private:
std::string* ps;
int i;
size_t* use;
};