当您拥有"远程所有权"时,浅拷贝会导致问题(主要是).最常见的形式是指向对象拥有的数据的指针,因此当对象被销毁时,它拥有的数据也会被销毁.许多人遇到的一个地方是不可避免的字符串类:
// warning: bad code. Do *not* use.
class mystring {
char *data;
public:
mystring() : data(NULL) {}
mystring(char *init) {
data = new char[strlen(init)+1];
strcpy(data, init);
}
~mystring() { delete [] data; }
};
int main() {
mystring s("This is a string");
mystring t;
t = s;
}
Run Code Online (Sandbox Code Playgroud)
这将编译得很好.在这些确切的情况下,它甚至可能运行良好.这并不意味着它确实是对的.当我们分配s时t,指针被复制,但它指向的内容不会被复制.我们有两个对象都包含指向同一缓冲区的指针.当其中一个被破坏时,它会删除数据的相关缓冲区.然后我们有一个悬空指针 - 它仍然试图引用缓冲区,但缓冲区不再存在.当第二个对象被破坏时,它将尝试再次释放相同的内存 - 但由于它已经被释放,这导致了未定义的行为(即,任何事情都可能发生,而且通常会发生一些不好的事情).
浅拷贝有两种常见的替代方法.一个是"深度"副本,我们在其中重载类的复制构造函数和赋值运算符,当我们复制/分配对象时,我们分配一个新缓冲区并将旧缓冲区的内容复制到新缓冲区.
第二个是引用计数.我们使用指向缓冲区的"智能"指针而不是指向缓冲区的"原始"指针.智能指针跟踪有多少对象引用缓冲区,并且只有在没有任何引用时才释放缓冲区本身.
两者都不是完全完美的:深度复制可能很慢并且使用大量内存,尤其是涉及大量数据时.在多线程环境中引用计数可能很慢 - 因为可以从多个线程访问引用计数,所以必须保护它以确保只有一个线程一次修改它(通常至少比一个线程慢一个数量级)正常增量/减量).
| 归档时间: |
|
| 查看次数: |
2401 次 |
| 最近记录: |