[英]how the destructor works in c++
这是我的c ++代码:
class Sample
{
public:
int *ptr;
Sample(int i)
{
ptr = new int(i);
}
~Sample()
{
delete ptr;
}
void PrintVal()
{
cout << "The value is " << *ptr;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
它返回我的输出,如:
Say i am in someFunc
Null pointer assignment(Run-time error)
这里,当对象通过值传递给SomeFunc时,控件从函数返回时会调用该对象的析构函数
我应该对吗? 如果是,那为什么会发生? 什么解决方案?
由于你有一个指针成员,你通常需要遵守三法则 。
在您的代码示例中,为了避免您看到的未定义行为:
通过必须先声明更换需要 。
Sample
通过值传递给SomeFunc
,这意味着要进行复制。 副本具有相同的ptr
,因此当SomeFunc
返回时销毁该副本时,将删除两个对象的ptr
。 然后,当您在main中调用PrintVal()
,您将取消引用此无效指针。 这是未定义的行为。 即使有效,那么当s1
被破坏时, ptr
也会被删除,这也是UB。
此外,如果编译器未能删除Sample s1= 10;
的副本Sample s1= 10;
然后s1
甚至无法开始有效,因为当临时被销毁时,指针将被删除。 大多数编译器确实避免使用此副本。
您需要正确实现复制或禁止复制。 此类型的默认copy-ctor不正确。 我建议将此类型设置为值类型(直接保存其成员而不是指针),以便默认的copy-ctor可以工作,或者使用智能指针来保存引用,以便它可以管理引用资源您和默认的copy-ctor仍然有效。
我真正喜欢C ++的一个原因是它对于在任何地方使用值类型都非常友好,如果你需要一个引用类型,你可以在智能指针中包装任何值类型。 我认为这比具有值语义的原始类型的其他语言更好,但是用户定义的类型默认具有引用语义。
由于SomeFunc()
按值获取其参数,因此将传递传递给它的Sample
对象。 当SomeFunc()
返回时,临时副本将被销毁。
由于Sample
没有定义复制构造函数,因此其编译器生成的复制构造函数只是复制指针值,因此两个Sample
实例都指向相同的int
。 当一个Sample
(临时副本)被销毁时,该int
被删除,然后当第二个Sample
(原始)被销毁时,它会再次尝试删除相同的int
。 这就是你的程序崩溃的原因。
您可以更改SomeFunc()
以获取引用,避免临时副本:
void someFunc(Sample const &x)
和/或您可以为Sample
定义一个复制构造函数,它分配一个新的int
而不是仅仅将指针复制到现有的指针。
当您传递函数的参数时,它被称为复制构造函数,但是您没有它,因此指针未初始化。 当它退出函数时,对象调用析构函数来删除单元化指针,因此它会产生错误。
代替
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
试着用
int main()
{
Sample* s1= new Sample(10);
SomeFunc(*s1);
s1->PrintVal();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.