我试图理解复制构造函数的概念。我用这个例子:
#include <iostream>
using namespace std;
class Line
{
public:
int GetLength();
Line(int len);
Line(const Line &obj);
~Line();
private:
int *ptr;
};
Line::Line(int len)
{
ptr = new int;
*ptr = len;
};
Line::Line(const Line &obj)
{
cout << "Copying... " << endl;
ptr = new int;
*ptr = *obj.ptr;
};
Line::~Line()
{
delete ptr;
};
int Line::GetLength()
{
return *ptr;
}
int main()
{
Line line1 = Line(4);
cout << line1.GetLength() << endl;
Line line2 = line1;
line1.~Line();
cout << line2.GetLength() << endl;
return 0;
}
问题是,为什么我在这里遇到运行时错误?如果我定义了一个复制构造函数,它为新的ptr分配内存,并将line1分配给line2,那是不是意味着这两个是单独的对象?通过破坏line1,我显然也搞乱了line2,或者我使用析构函数调用错了?
答案 0 :(得分:7)
您在此声明中调用了析构函数
line1.~Line();
删除了为ptr
Line::~Line()
{
delete ptr;
};
然而,对象line1
仍然存在,因为它具有自动存储持续时间。因此,在退出main之后,将再次调用该对象的析构函数,因此它将尝试删除已明确删除的ptr
指向的内存。
答案 1 :(得分:0)
line1.~Line();
仅当您使用展示位置新时,手动调用析构函数才有用。
我不明白是什么让你想到在这个程序中手动调用析构函数。当你还不熟悉这种语言时,你真的不想知道这种低级别的内存管理机制,但为了完整起见,它会像这样工作:
int main()
{
// provide static memory with enough space for one Line object:
char buffer[sizeof(Line)];
// create a Line object and place it into buffer:
Line* line1 = new (buffer) Line(4);
cout << line1->GetLength() << endl;
Line line2 = *line1;
// manually call the destructor:
line1->~Line();
cout << line2.GetLength() << endl;
// - no delete necessary because buffer disappears automatically
// - no automatic destructor call
return 0;
}
但是,您的代码会导致尝试两次调用line1
的析构函数。首先手动,然后在对象的范围结束时自动,即在main
结束时。这是未定义的行为。见Does explicitly calling destructor result in Undefined Behavior here?
问题是,为什么我在这里遇到运行时错误?
因为未定义的行为意味着您的程序可以执行或不执行任何操作。不保证运行时错误,也不保证任何确定性行为。