析构函数如何在c ++中工作

时间:2012-01-23 17:07:51

标签: c++ oop destructor

这是我的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时,当控件从函数返回时,将调用该对象的析构函数

我应该对吗?如果是,那为什么会发生?什么解决方案????

5 个答案:

答案 0 :(得分:5)

您通常需要遵守 Rule of Three ,因为您有指针成员。
在您的代码示例中,为了避免您看到的未定义行为:

必须的第一个语句中替换需要

答案 1 :(得分:5)

Sample按值传递给SomeFunc,表示复制。副本具有相同的ptr,因此当SomeFunc返回时销毁该副本时,将删除两个对象的ptr。然后当你在main中调用PrintVal()时,你取消引用这个无效指针。这是未定义的行为。即使有效,那么当s1被销毁时ptr会再次被删除,这也是UB。

此外,如果编译器无法忽略Sample s1= 10;中的副本,那么s1甚至无法开始有效,因为当临时被销毁时,指针将被删除。大多数编译器确实避免使用此副本。

您需要正确实施复制或禁止复制。此类型的默认copy-ctor不正确。我建议将此类型设置为值类型(直接保存其成员而不是指针),以便默认的copy-ctor可以工作,或者使用智能指针来保存引用,以便它可以管理引用资源你和默认的copy-ctor仍然有用。

我真正喜欢C ++的一个原因是它对于在任何地方使用值类型非常友好,如果你需要一个引用类型,你可以在智能指针中包装任何值类型。我认为这比具有值语义的原始类型的其他语言要好得多,但是默认情况下用户定义的类型具有引用语义。

答案 2 :(得分:1)

由于SomeFunc()按值获取其参数,因此会复制传递给它的Sample对象。当SomeFunc()返回时,临时副本将被销毁。

由于Sample没有定义复制构造函数,因此其编译器生成的复制构造函数只是复制指针值,因此两个Sample实例都指向相同的int。当一个Sample(临时副本)被销毁时,int被删除,然后当第二个Sample(原始)被销毁时,它会尝试删除相同的int SomeFunc()再次。这就是你的程序崩溃的原因。

您可以更改void someFunc(Sample const &x) 以取代引用,避免使用临时副本:

Sample

和/或您可以为int定义一个复制构造函数,它分配一个新的{{1}},而不是仅仅将指针复制到现有的。{/ p>

答案 3 :(得分:0)

当您传递函数的参数时,它被称为复制构造函数,但是您没有它,因此指针未初始化。当它退出函数时,对象调用析构函数来删除单元化指针,因此它会产生错误。

答案 4 :(得分:0)

而不是

int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}

尝试使用

int main()
{
Sample* s1= new Sample(10);
SomeFunc(*s1);
s1->PrintVal();
}