关于C析构函数

前端之家收集整理的这篇文章主要介绍了关于C析构函数前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
每个人
我有一些 java经验,是c的初学者.
belw是我的代码,它的输出
0 1 2 3 4 5 6 7 8 9
destructor ---s1
8791616 8785704 2
destructor ---s1

我预计输出

0 1 2 3 4 5 6 7 8 9
destructor ---abc
0 1 2
destructor ---s1

我无法理解为什么析构函数释放第一个对象的资源.
如何打印我预期的输出

#include <iostream>
using namespace std;
class Sequence{
    public:
        Sequence(int count=10,string name = "abc");
        void show();
        ~Sequence();

        int* _content;
        int _count;
        string _name;

};

Sequence::Sequence(int count,string name){
    _count = count;
    _content=new int[count];
    _name = name;
    for(int i=0;i<count;i++){
        _content[i]=i;
    }
}

Sequence::~Sequence(){
    cout << "destructor ---"<<_name<<endl;
    delete [] _content;
}

void Sequence::show(){
    for(int i=0;i<_count;i++)
        cout<<_content[i]<<" ";
    cout<<endl;
}

int main(){
    Sequence s1 = Sequence();
    s1.show();
    s1 = Sequence(3,"s1");
    s1.show();
}

解决方法

如果你提高编译器的警告级别,你会得到一个提示,你的类包含指针,但你没有定义Sequence(const Sequence&)或operator =(const Sequence&)(见 What is The Rule of Three?).

因为您没有提供复制构造函数或赋值运算符,所以编译器会为您提供这些,它们执行成员分配.

当您调用s1 = Sequence(3,“s1”);时,您正在执行以下操作(这对Java开发人员来说可能是意外的):

>创建一个新的,临时的,三个序列,其名称为“s1”
>将其分配给s1,其中:

>将si._content设置为指向刚刚创建的三个整数的新数组的指针,泄漏旧的10个整数.
>将si._count设置为3
>将si._name设置为“s1”

>然后销毁临时(而不是s1)(在上面的实际输出中,你看到“s1”被销毁两次),留下_content指向free’d内存(这就是你在第二次调用s1时看到垃圾的原因.节目()).

如果您声明这样的赋值运算符,您将获得更接近预期输出内容

Sequence& operator =(const Sequence& rhs)
{
    if (this != &rhs)
    {
        delete [] _content;

        _count = rhs._count;
        _content = new int[_count];
        _name = rhs._name + " (copy)";
        for (int i = 0; i < _count ; ++i)
        {
            _content[i] = rhs._content[i];
        }
    }
    return *this;
}

但是,你不会看到:

destructor ---abc

…因为你的_name包含“abc”时不会销毁s1.

s1在结束时超出范围时被销毁,这就是你看到第二个析构函数调用的原因.使用您的代码,这会再次调用s1._content上的delete [](它会在临时删除,您会记得).这可能会导致程序结束时发生崩溃.

我在我的赋值运算符中为_name添加了“(copy)”来帮助说明这里发生了什么.

还请看一下What is the copy-and-swap idiom?,这是处理带有原始指针的类的非常简洁的方法.这也会产生你想要的输出,因为_c为“abc”的s1实例被换出并销毁.我已经实现了这个here,以及其他一些小改进,以便您可以看到它正常工作.

N.B:创建类实例的规范方法是:

Sequence s1; // Default constructor. Do not use parentheses [http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.2]!
Sequence s2(3,"s2") // Constructor with parameters

猜你在找的C&C++相关文章