operator + overload返回导致内存泄漏的对象,C ++

时间:2010-04-09 02:26:57

标签: c++

我认为问题是当我重载+运算符时返回一个对象。我尝试返回对该对象的引用,但这样做并不能解决内存泄漏问题。我可以评论这两个陈述:

dObj = dObj + dObj2;

cObj = cObj + cObj2;

释放内存泄漏程序。不知何故,问题是在重载+运算符后返回一个对象。

    #include <iostream>
    #include <vld.h>

    using namespace std;

    class Animal
    {
    public :
        Animal() {};
        virtual void eat()  = 0 {};
        virtual void walk() = 0 {};
    };

    class Dog : public Animal
    {
    public :
        Dog(const char * name, const char * gender, int age);
        Dog() : name(NULL), gender(NULL), age(0) {};

        virtual ~Dog();
        Dog operator+(const Dog &dObj);

    private :
        char * name;
        char * gender;
        int age;
    };

    class MyClass
    {
    public :
        MyClass() : action(NULL) {};
        void setInstance(Animal &newInstance);
        void doSomething();

    private :
        Animal * action;
    };


    Dog::Dog(const char * name, const char * gender, int age) :  // allocating here, for data passed in ctor
            name(new char[strlen(name)+1]), gender(new char[strlen(gender)+1]), age(age)
    {
        if (name)
        {
            size_t length = strlen(name) +1;
            strcpy_s(this->name, length, name);
        }
        else name = NULL;
        if (gender)
        {
            size_t length = strlen(gender) +1;
            strcpy_s(this->gender, length, gender);
        }
        else gender = NULL;
        if (age)
        {
            this->age = age;
        }
    }
    Dog::~Dog()
    {
        delete name;
        delete gender;
        age = 0;
    }

    Dog Dog::operator+(const Dog &dObj)
    {
        Dog d;
        d.age = age + dObj.age;
        return d;
    }

    void MyClass::setInstance(Animal &newInstance)
    {
        action = &newInstance;
    }
    void MyClass::doSomething()
    {
        action->walk();
        action->eat();  
    }
    int main()
    {
        MyClass mObj;

        Dog dObj("Scruffy", "Male", 4); // passing data into ctor
        Dog dObj2("Scooby", "Male", 6);

        mObj.setInstance(dObj); // set the instance specific to the object.
        mObj.doSomething();  // something happens based on which object is passed in

        dObj = dObj + dObj2; // invoke the operator+ 
        return 0;
    }

11 个答案:

答案 0 :(得分:5)

如果您打算进行自己的内存管理(不应该;使用std::string!),您需要确保您的类具有以下用户定义功能:

  • 一个析构函数
  • 复制构造函数
  • 指派运算符

(此外,您通常也会有一个用户定义的构造函数)

你有一个用户定义的析构函数(认为你需要使用数组delete[],而不是标量delete),但你没有用户定义的复制构造函数或赋值运算符,所以无论何时复制对象或分配对象,它最终都会进行成员复制。然后两个对象具有相同的指针,当它们都被销毁时,指针会被删除两次 - 这是一个很大的禁忌。

答案 1 :(得分:4)

你需要声明复制构造函数,因为你在重载的operator +中返回对象,如果你没有明确地定义它,编译器会自动为你生成一个,但编译器是愚蠢的,不能对指针进行深层复制

总结您在发布的代码中的错误:

1。)没有Copy-Constructor / Assignment-Operator定义(释放异常/内存泄漏
由于您正在处理指针,因此编译器生成的函数仅执行浅拷贝 你应该确保这样的行为是有意的,否则你自己重新定义为:

Dog::Dog(const Dog& ref) :
_name( strdup(ref._name) ), 
_gender( strdup(ref._gender) ), 
_age( ref._age )
{
}

Dog& Dog::operator=(const Dog &dObj)
{
    if (this != &dObj)
    {
        free (_name);
        free (_gender);
        _name = strdup( dObj._name );
        _gender = strdup( dObj._gender );
        _age = dObj._age;
    }
    return *this;
}

2。)传入指针的处理不当(内存泄漏
您在验证输入参数的空状态之前执行了分配。
另外额外分配1个内存char是明智之举,但是在找到输入参数为null之后你不会释放它们。类似于上面的copy-constructor的简单修复将是:

Dog::Dog(const char * name, const char * gender, int age) :
_name( strdup(name) ), 
_gender( strdup(gender) ), 
_age( age )
{
}

3。)分配器/解除分配器的配对不正确(潜在的内存泄漏
使用new []的数组分配应该与数组释放delete []匹配,否则将无法正确处理数组元素的析构函数。
但是,为了与上面使用strdup(内部使用malloc)发布的示例代码一致,您的析构函数应如下所示:

Dog::~Dog()
{
    free (_name);
    free (_gender);
    _age = 0;
}

答案 2 :(得分:4)

使用std::string,您的所有问题都会消失。 毕竟您将问题标记为C ++,因此您应该使用C ++标准库。绝对没有理由不使用std::string

当然,您不需要使用char*分配,因为这个问题不是家庭作业,因为它没有被标记为家庭作业。对?

答案 3 :(得分:1)

另一个切线错误:在调用+运算符和赋值运算符之后,dObj.namedObj.gender现在为空,因为Dog d声明为{{1}中的返回值使用默认构造函数创建,并且在返回新对象之前未重新分配operator+name

答案 4 :(得分:0)

我认为可能是因为:

delete[] name;
delete[] gender;

答案 5 :(得分:0)

你正在分配名称&amp;性别为new char[],因此您需要使用delete [] name;取消分配。无论何时分配数组,都必须删除该数组。

正如评论所指出的那样,省去麻烦并使用std :: string! :)

答案 6 :(得分:0)

问题在于

Dog::Dog(const char * name, const char * gender, int age) :  // allocating here, for data passed in ctor
            name(new char[strlen(name)+1]), gender(new char[strlen(gender)+1]), age(age)

Dog::~Dog()
{
    delete name;
    delete gender;
    age = 0;
}

您的new[]需要与delete[]匹配,而不是delete.

答案 7 :(得分:0)

每个人都给出了泄漏的原因

有一件事我想指出

Dog::~Dog()
{
    delete name;
    delete gender;
    age = 0;
}

没有必要执行age=0,这是无用的,因为对象在析构函数后不再存在。

答案 8 :(得分:0)

您需要一个复制构造函数,在复制新对象之前删除旧对象上的内存。问题是:

dObj = dObj + dObj2;

+的结果是用NULL来覆盖dObj的旧char *(来自运算符+中的返回对象),而不首先解除那些char *。

答案 9 :(得分:0)

虽然它不会影响你的问题(因为你没有动态分配任何Dog),如果你是在{{{}中声明虚拟~Dog析构函数1}}类,你可能还需要在Dog类中声明一个虚拟的~Animal析构函数,即使它什么都不做。

那样,如果你:

Animal

然后将调用Animal* a=new Dog(); delete a; 的析构函数。

答案 10 :(得分:0)

这不是导致内存泄漏的原因,但是您的Animal类需要有一个虚拟析构函数。否则,如果你要写:

Animal *dog = new Dog("Spot", "Male", 5);
delete dog;

然后即使在修复任何其他问题之后你也会泄漏内存,因为在Animal类中没有虚拟析构函数,Dog析构函数永远不会被调用以释放Dog中分配的内存1}}构造函数。

这种情况在您的情况下没有发生,因为您在堆栈上创建了Dogs作为自动变量,这很好。