我认为问题是当我重载+运算符时返回一个对象。我尝试返回对该对象的引用,但这样做并不能解决内存泄漏问题。我可以评论这两个陈述:
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;
}
答案 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.name
和dObj.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作为自动变量,这很好。