我在c ++方面很不错,但在指针和内存方面,我总是很糟糕。我已经陷入了这种情况,我不知道是否有解决方案。
typedef unsigned long long ullong;
class MathClass { //This is just an example class
public:
MathClass() {num = new ullong[1]();}
MathClass operator+(MathClass b) { //This is not my actual function, just one that has the same problem
MathClass c;
c.num[0] = num[0] + b.num[0];
delete [] num;
num = NULL;
return c;
}
public:
ullong* num;
};
这适用于这种情况。
MathClass a;
MathClass b;
for (int i = 0; i < 1000; i++) {
a = a + b;
}
因为我设置的等于a + b,所以当+函数运行时,它会设置等于c并删除旧的数字。
对于这种情况,它会导致错误,因为我删除了b&#39;
MathClass a;
MathClass b;
MathClass c;
for (int i = 0; i < 1000; i++) {
a = b + c;
}
如果我没有删除num,这将起作用,但这会导致内存泄漏。当我不删除num时,这个内存容易超过100MB。我确定答案很简单,但我无法弄清楚。
答案 0 :(得分:0)
你需要三(五)的规则。
当你分配内存,或者你需要实现赋值,析构函数或复制构造函数时,你需要全部三个(五个 - 移动构造函数和移动赋值)。
当您使用new分配内存时(请考虑shared_ptr,unique_ptr),您需要控制复制分配和删除的工作方式。
class MathClass { //This is just an example class
public:
MathClass() {num = new ullong[1]();}
~MathClass() { delete [] num;} // cleans up memory.
MathClass( const MathClass & rhs ) { num = new ullong[1](); num[0] = rhs.num[0]; }
MathClass& operator=( const MathClass & rhs )
{
if( &rhs != this ) {
num[0] = rhs.num[0];
}
return *this;
}
MathClass operator+(MathClass b) { //This is not my actual function, just one that has the same problem
MathClass c;
c.num[0] = num[0] + b.num[0];
// the wrong place delete [] num;
num = NULL;
return c;
}
public:
ullong* num;
};
operator +中的delete []位于错误的位置,因为它试图找到释放内存的正确位置。但是,最简单的方法就是应用rule of 3并确保内存在构造时构造,删除时删除,并且赋值(和移动)运算符正常工作
答案 1 :(得分:0)
问题实际上并不完全在指针中,而是运算符重载和类实现(如注释中所述)。 如果你在第一个例子中使用了争论者(即a = a + b - > a = b + a),你会看到与第二个例子中相同的错误。所以这里有关于实施operator overloading的好文章 代码看起来像这样
#include <iostream>
#include <algorithm>
typedef unsigned long long ullong;
class MathClass {
public:
MathClass() { num = new ullong[ 1 ](); }
MathClass( const MathClass &a ) {
*this = a;
}
~MathClass() {
delete[] num;
num = NULL;
}
MathClass &operator=( const MathClass &a ) {
if ( this != &a ) {
num = NULL;
num = new ullong[ 1 ];
}
std::copy( a.num, a.num + 1, num );
return *this;
}
friend MathClass operator+( const MathClass &a, const MathClass b ) {
MathClass c;
c.num[ 0 ] = a.num[ 0 ] + b.num[ 0 ];
return c;
}
ullong *num;
};
int main( int argc, char **argv ) {
MathClass a;
MathClass b;
MathClass c;
for ( int i = 0; i < 1000; ++i ) {
std::cout << "a.num[ 0 ] is " << a.num[ 0 ] << std::endl;
std::cout << "b.num[ 0 ] is " << b.num[ 0 ] << std::endl;
a = b + a;
a = c + b;
}
return 0;
}
在主要&#34; std :: cout&#34;仅用于输出可见性。当然我的复制构造函数的实现要好得多,但这里的关键点是当你使用coplex类型时,你几乎总是需要重新实现复制和赋值操作符,因为它们经常(如果不是总是)被调用。
还有一些其他时刻可以提及您的代码。至少自C ++ 11 NULL更改为nullptr
以来,typedef
也不常见。使用引用而不是指针,这是一个很好的做法,特别是在复杂参数的情况下,通过引用传递它们,而不是通过值,因为在传递值的情况下,将调用复制构造函数,并且您将必须具有相同的参数的实例,这可以导致记忆过度使用。