shared_ptr
就是一个很好的例子:复制对象表示会给你第二个指向同一对象的指针,但不会增加使用次数。一旦你已经打破了不变的使用计数必须等于指针的数量,你会把自己暴露给未定义的行为,如提领悬摆指针,并删除同样的对象两次:
shared_ptr<int> good(new int(42));
shared_ptr<int> evil;
memcpy(&evil, &good, sizeof evil); // Breaking invariant
good.reset(); // Deletes object
*evil = 666; // BOOM! accesses deleted object
evil.reset(); // BOOM! deletes object a second time.
你还别说虚函数。如果您复制派生类的基础子对象,这些可能会导致问题;产生的对象将(可能)指向虚拟表的错误类:
struct Base {
virtual int f() {return 0;}
};
struct Derived : Base {
int x;
virtual int f() {return x;}
};
Base * good = new Derived;
Base evil;
memcpy(*evil, good, sizeof evil); // Base object with Derived vtable (probably)
evil->f(); // BOOM! probably accesses nonexistent member `x`
memcpy non-POD是未定义的行为。这是一个肯定的声明(这是真的)。什么是问题? – 2013-02-21 10:16:45
'memcpy'' shared_ptr'几乎可以保证访问释放的内存,并且可能还会进行双重删除。仅仅因为一个简单的例子不会崩溃并不意味着它可以工作。 – 2013-02-21 10:34:43
我认为不会崩溃比在这种情况下崩溃更糟糕。在一个更复杂的系统中,你将会处理垃圾数据,这将是一个令人困惑的头痛。 – kylefinn 2017-08-17 00:00:47