了解复制构造函数
Understanding Copy Constructor
我读到,如果我们的类中有指针,那么我们需要实现自己的复制构造函数;否则,两个类的指针将指向相同的内存位置,对其中一个类调用delete也会使另一个类为null。我正试图通过编写这样的代码来模拟上述情况:
class A
{
private:
int *p;
public:
A()
{
p = new int(10);
}
~A()
{
delete p;
cout << "Calling destructor" << endl;
}
};
int main(int argc, char **argv)
{
A a;
A aa = a;
}
我预计会抛出一些异常,因为我还没有明确声明我的复制构造函数,而且我也在使用指针。但程序运行得很完美。有人能提出修改建议吗?这样我就能理解在什么情况下会发生异常?
您的代码对同一指针执行delete
两次。这是不明确的行为,以及未定义的行为是,它似乎可以工作。(在我的经验,最常见的症状是一切正常直到你把它呈现给公众,在这个时候,它开始左右碰撞。)
您的问题与两个指针指向一个实例并删除该实例相同。
给定以下代码:
int main(void)
{
int * pointer_1 = NULL;
int * pointer_2 = NULL;
pointer_1 = new int;
*pointer_1 = 42;
// Make both pointers point to the same dynamically allocated object.
pointer_2 = pointer_1;
// Let's delete the instance
delete pointer_1;
// The delete operator does not change the value of pointer_1.
// Pointer_1 still points to *something*, but that *something* has been deleted.
return 0;
}
在上述示例中,delete
不影响pointer_1
或pointer_2
的值。只有物体不在了。在C或C++标准中,没有任何规定在删除内存或更改指针时必须通知程序。
没有任何内容表明,当删除内存时,实现必须更改指向已删除内存的每个指针。
因为对象已经不在了,所以推迟指针将生成未定义的行为。内容可能在内存中有阴影,或者操作系统可能已将页面完全从内存中删除(也称为内存分页)。
操作系统可能会抛出异常,但C和C++语言不会强制编译器库生成异常。毕竟,在一些嵌入式系统中,地址0是一个有效的内存位置。
尝试在每个步骤打印指针的值以进行验证。
我告诉你和你的朋友指着地板上的一块地毯。我把地毯拿掉。你和你的朋友在指什么?
类似的东西
A * a = new A();
A * b = a;
delete a;
stdout << (*(b->p));
但是delete
应该只为程序的其他部分腾出内存,而不一定是null
。
我不认为这会引发"异常"。您可能会出现不良副作用,如SEGV或更严重的内存损坏。要理解为什么需要复制构造函数,可以考虑对象"a"answers"aa"的外观。
假设new int(10)返回一个指针值0xfeedface,其中*(int*)(0xfeedfface)==10。你的物体看起来像
a->{p=0xfeedface}aa->{p=0xfeedface}
现在,如果您销毁对象-内存"0xfeedfac"将未分配&回到您的分配器免费列表。想想对象aa发生了什么。它仍然保存着对0xfeedface的引用,但该内存已经被释放!现在,如果对象aa试图取消引用*p,它可以获得潜在的随机值(取决于分配器的操作,或者对象是否已分配给其他对象)。此外,如果对象aa试图写入p=0xfeedface,那么可能会发生可怕的事情。
如果你想强制编写一个复制构造函数,我可以想到的一种方法是创建一个基类&断言是否被调用。
#include <iostream>
#include <cassert>
class base
{
public:
virtual void operator=(const base& )
{
assert(! "No copy constructor for class derived from base");
}
};
class derived : public base
{};
int
main()
{
derived d, d1;
d1 = d;
}
上面的代码将断言,因为派生类没有提供复制构造函数。最好是在编译时捕获它。但我现在想不出什么办法。
[注意:上面的解决方案不能很好地用于多个继承级别]
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 当从函数参数中的临时值调用复制构造函数时
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 使用复制构造函数复制双精度数组
- C 无可行的构造函数复制类型的变量
- 没有可行的构造函数复制类型 'MyString' 的数组元素
- 编译时,复制构造函数/复制分配和正常功能调用优化之间是否存在任何区别
- 如何最小化调用列表构造函数(复制构造函数)的次数?
- C 11矢量构造函数复制与范围
- 我定义了一个非复制构造函数;复制构造函数还会被隐式定义吗
- 可以将构造函数复制为转换运算符
- 将基类指针的构造函数复制到子类
- C++树类:构造函数/复制/内存泄漏
- 如何制作这个在模板构造函数复制中使用类型定义的类型的模板
- 将构造函数复制为模板化的成员函数
- 绕过私有复制构造函数/复制赋值C++
- C++通过构造函数复制对象
- 复制构造函数 - 复制C++中的对象
- 将带unique_ptr的类的构造函数复制到作为成员的抽象类