您不能只删除使用创建的数组的一部分new
。new
分配一块只能一起delete
编辑的内存块。
如果你想让一个对象释放它自己的内部数据,你必须安排这个应该封装和隐藏它自己的内部资源的类来自己做。
如果您想要一个较小的内存块来保存您分配的数组,那么您必须分配一个较小的块并将您希望保留的内容移动到新块中,然后删除整个旧块:
int *arr = new int[10];
int *tmp = new int[9];
std::copy(arr+1, arr+10, tmp);
delete [] arr;
arr = tmp;
你需要设计你的类来管理它自己的资源,并处理复制或移动。您的 currentmyClass
分配了一个数组,但依赖于其他代码来处理清理。这不是做这件事的好方法,因为通常没有其他代码可以做正确的事情,即使你可以,你也会经常犯错误。
由于您在构造函数中进行分配,因此您需要一个处理释放的析构函数。然后,由于您实现了三个特殊操作之一(copy-ctor、copy-assignment、析构函数),您需要考虑全部实现它们。(这被称为“三法则”。在 C++11 中,它变成了“五法则”,并添加了 move-ctors 和 move assignment。)
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}) {}
现在,您想要的析构函数取决于您希望类具有的语义以及您想要维护的特定不变量。“值”语义是 C++ 中的规范(如果您熟悉 Java 或 C#,这些语言鼓励或要求用户定义类型的“参考”语义)。如果您想要值语义,并且如果您维护一个 num1 始终拥有内存或为空的不变量,则可以使用下面的析构函数。
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);
}