首先,区别初始化和赋值。初始化指为处于“混沌”状态的变量提供初始值,构造新的对象。变量初始化之前,它占用的内存区域的数据是未知的、无意义的,所以说它处于“混沌”的状态。严格地说,赋值指以参数值更新对象现有的值,在更新之前可能需要清理现有的资源,比如通过new申请的存储空间。参考下面的代码:
class StringPtr
{
public:
StringPtr() :
idx(++sidx),
ps(nullptr)
{
cout << "StringPtr(), " << *this << endl;
}
StringPtr(const string& s) :
idx(++sidx),
ps(new string(s))
{
cout << "StringPtr(const string&), " << *this << endl;
}
StringPtr(const StringPtr& obj) :
idx(++sidx)
{
assign(obj);
cout << "StringPtr(const StringPtr&), " << *this << endl;
}
StringPtr& operator=(const StringPtr& arg)
{
assign(arg);
cout << "StringPtr.operator=(const StringPtr&), " << *this << endl;
return *this;
}
~StringPtr()
{
cout << "~StringPtr(), " << *this << endl;
if (ps)
{
delete ps;
ps = nullptr;
}
}
friend ostream& operator<<(ostream& os, const StringPtr& sp);
private:
void assign(const StringPtr& arg)
{
if (&arg != this)
{
if (ps)
{
delete ps; // 释放之前通过new创建的对象
ps = nullptr;
}
if (arg.ps)
ps = new std::string(*arg.ps);
}
}
static int sidx;
int idx; // 唯一索引号,所有对象的索引不同
string* ps;
};
int StringPtr::sidx = 0;
ostream& operator<<(ostream& os, const StringPtr& sp)
{
os << "idx : " << sp.idx << ", ps : " << (sp.ps ? *sp.ps : "");
return os;
}
void example()
{
string s("2019-10-06");
StringPtr p1(s); // 初始化,调用StringPtr(const string&)
StringPtr p2(p1); // 初始化,调用StringPtr(const StringPtr&)
StringPtr p3 = p1; // 初始化,调用StringPtr(const StringPtr&)
StringPtr p4; // 初始化,调用StringPtr().这里没有提供初值,使用默认值.
p4 = p1; // 拷贝赋值,调用StringPtr.operator=(const StringPtr&)
}
考虑StringPtr p3 = p1;
,此处虽然使用了赋值运算符,但是变量p3尚未初始化,初始化之前它还不是StringPtr类型的对象,如何对它调用拷贝赋值运算呢?
有关初始化的详细内容,请参考:https://zh.cppreference.com/w/cpp/language/initialization