假设我们有这门课
struct BigArray{
int operator[](size_t i)const{return m_data[i];}
int& operator[](size_t i){return m_data[i];}
private:
int m_data[10000000];
};
现在说我们有两个实例:
BigArray a;
a[0]=1;//initializaation etc
BigArray b=a;
此时我们想要这个不变量
assert(a[0]==b[0]);
默认的复制 ctor 确保了这种不变性,但是以深度复制整个对象为代价。我们可能会尝试这样的加速
struct BigArray{
BigArray():m_data(new int[10000000]){}
int operator[](size_t i)const{return (*m_data)[i];}
int& operator[](size_t i){return (*m_data)[i];}
private:
shared_ptr<int> m_data;
};
这也将满足不变量,无需进行深拷贝,所以到目前为止一切都很好。现在使用我们所做的这个新实现
b[0]=2;
现在我们希望它与深拷贝案例 assert(a[0]!=b[0]); 一样工作。但它失败了。为了解决这个问题,我们需要稍作改动:
struct BigArray{
BigArray():m_data(new int[10000000]){}
int operator[](size_t i)const{return (*m_data)[i];}
int& operator[](size_t i){
if(!m_data.unique()){//"detach"
shared_ptr<int> _tmp(new int[10000000]);
memcpy(_tmp.get(),m_data.get(),10000000);
m_data=_tmp;
}
return (*m_data)[i];
}
private:
shared_ptr<int> m_data;
};
现在我们有了一个类,它在只需要 const 访问时进行浅拷贝,而在需要非常量访问时进行深拷贝。这就是“shared_data”指针概念背后的想法。const调用不会进行深度复制(他们称其为“分离”),而非 const 调用将在共享时进行深度复制。它还在 operator== 之上添加了一些语义,因此它不仅比较指针,而且还比较数据,这样就可以了:
BigArray b=a;//shallow copy
assert(a==b);//true
b[0]=a[0]+1;//deep copy
b[0]=a[0];//put it back
assert(a==b);//true
这种技术称为 COW(写时复制),自 C++ 出现以来就一直存在。它也非常脆弱——上面的例子似乎很有效,因为它很小并且用例很少。在实践中它很少值得麻烦,事实上 C++0x 已经弃用了 COW 字符串。所以谨慎使用。