从私有类变量中释放内存

时间:2012-11-18 05:59:20

标签: c++

#include <stdio.h>
#include <iostream>
#include <string>


using namespace std;

class myClass{

public:
    int *num1;
    myClass();


};

myClass::myClass(){
    num1 = new int[1];
    num1[0] = 10;
}


int main()
{
    myClass *myclass;

    myclass = new myClass[10];

    cout << myclass[0].num1[0] << endl;

    delete &myclass[0];
    cout << myclass[0].num1[0] << endl;

}

我想删除myclass的第一个实例(myclass [0])。

此代码无法正常运行,在删除部分失败。可能有一些我缺少的东西。

我做错了什么?

2 个答案:

答案 0 :(得分:2)

您不能仅删除使用new创建的数组的一部分。 new分配一块只能delete一起编写的内存块。

如果你想让一个对象释放自己的内部数据,你必须安排这个类,它应该封装和隐藏自己的内部资源,以便自己完成。

如果你想要一个较小的内存块来保存你分配的数组,那么你必须分配一个较小的块并将你希望保留的内容移动到新块中,然后删除整个旧块:

int *arr = new int[10];

int *tmp = new int[9];
std::copy(arr+1, arr+10, tmp);
delete [] arr;
arr = tmp;

您需要设计您的类来管理自己的资源,并处理复制或移动。您当前的myClass分配一个数组,但依赖其他代码来处理清理。这不是一个很好的方法,因为通常没有其他代码可以做正确的事情,即使你可能经常犯错误。

由于您在构造函数中分配,因此需要一个处理释放的析构函数。然后,由于您实现了三个特殊操作之一(copy-ctor,copy-assignment,析构函数),因此您需要考虑全部实现它们。 (这被称为“三个规则”。在C ++ 11中,它增加了移动控制和移动分配,成为'五规则'。)

class myClass {
public:
    myClass();

    // destructor to handle destroying internal resources correctly
    ~myClass();

    // copy constructor and copy assignment operator, to handle copying correctly
    myClass(myClass const &rhs);
    myClass &operator=(myClass const &rhs);

    // move constructor and move assignment operator, to handle moves correctly (C++11)
    myClass(myClass && rhs);
    myClass &operator= (myClass &&rhs);

private:
   int *num1; // private so external code can't screw it up

public:
   // limited access to num1
   int size() const { if (num1) return 1; else return 0; }
   int &operator[] (size_t i) { return num1[i]; }
};

你可以像你一样实现构造函数,或者你可以使用初始化列表和C ++ 11统一初始化:

myClass::myClass() : num1(new int[1]{10}) {}

现在,您想要的析构函数取决于您希望该类具有的语义,以及您想要维护的特定不变量。 'value'语义是C ++中的标准(如果您熟悉Java或C#,那些语言鼓励或要求用户定义类型的'引用'语义)。如果你想要值语义,那么你可以使用这个析构函数,如果你保持一个不变量,num1总是拥有内存或者是null。

myClass::~myClass() { delete num1; }

可以通过不同方式处理复制和移动。如果你想完全禁止它们,你可以说(在C ++ 11中):

myClass::myClass(myClass const &rhs) = delete;
myClass &myClass::operator=(myClass const &rhs) = delete;

myClass::myClass(myClass && rhs) = delete;
myClass &myClass::operator= (myClass &&rhs) = delete;

或者如果你想允许复制和/或移动(并维护上面提到的值语义和不变量),那么你可以实现这些函数对中的一个或两个:

myClass::myClass(myClass const &rhs) : num1( rhs.size() ? new int[1]{rhs[0]} : nullptr) {}
myClass &myClass::operator=(myClass const &rhs) {
    if (num1)
        num1[0] = rhs[0];
}

myClass::myClass(myClass && rhs) : num1(rhs.num1) { rhs.num1 = nullptr; } // remember to maintain the invariant that num1 owns the thing it points at, and since raw pointers don't handle shared ownership only one thing can own the int, and therefore only one myClass may point at it. rhs.num1 must be made to point at something else...
myClass &myClass::operator= (myClass &&rhs) { std::swap(num1, rhs.num1); } // steal rhs.num1 and leave it to rhs to destroy our own num1 if necessary. We could also destroy it ourselves if we wanted to.

通过此实现,您现在可以像处理int或任何其他“值”类型一样处理myClass对象。您不再需要担心管理其内部资源;它会自己照顾它们。

int main() {
    std::vector<myClass> myclassvec(10);

    cout << myclassvec[0][0] << '\n';

    myclassvec.erase(myclassvec.begin()); // erase the first element

    cout << myclassvec[0][0] << '\n'; // access the new first element (previously the second element);
}

答案 1 :(得分:1)

在类中创建一个函数来处理其私有成员的删除,可能称为FreeMem(int index)

void myClass::FreeMem()
{
    delete [] num1
}

但老实说,在这种程序中不使用析构函数释放对象的记忆是危险且彻头彻尾的不良做法。我建议在析构函数中释放内存,所以当对象终止时它会释放内存,

myClass::~myClass()
{
    delete [] num1;
}

另外需要注意的是,如果您只在动态变量中创建一个值,则将其编写为:

int * pnum = new int;
//or in your class..
pnum = new int;

除此之外,你的程序中存在很多缺陷。我建议你重新阅读课程。