delete[] 是否适用于通用数组?如果是这样,为什么在其上使用 std::vector::erase 会导致释放内存时出错
Does delete[] work properly with generic arrays? If so why does using std::vector::erase on it cause error in freeing memory
我试图使用圆形数组,因此最终编写了一个 CircularArray class,我已为其附加了代码。它使用数组的通用指针。
当我尝试使用 std::vector 创建此类圆形数组的列表时,我在尝试对其使用擦除时遇到问题。
我不明白为什么会这样,因为我认为析构函数和复制构造函数正常工作得很好。
有人可以帮忙吗?
代码:
循环数组 Class
template<class T> class CircularArray
{
//Class denoted by 'T' is expected to have a functional assignment operator, i.e. operator=(const T& ext) {} in place
protected:
int size=0;
int ori=0;
T* array;
private:
int pos=0;
public:
CircularArray() : CircularArray(0) {}
CircularArray(int s) {size=s;array=new T[s];}
CircularArray(T* ptr,int s)// : CircularArray(s)
{
size=s;array=new T[s];
for(int i=0;i<size;i++)
array[i]=ptr[i];
}
CircularArray(const CircularArray<T>& arr) : CircularArray(arr.size)
{
for(int i=0;i<size;i++)
array[i]=arr.array[i];
}
~CircularArray() {delete[] array;}
...
测试代码
int main()
{
std::vector<CircularArray<int>> test;
int *a1=new int[3] {1,2,3},*a2=new int[3] {1,2,3},*a3=new int[3] {1,2,3};
CircularArray<int> n1(a1,3),n2(a2,3),n3(a3,3);
test.push_back(n1);
test.push_back(n2);
test.push_back(n3);
test.erase(test.begin()+1);
for(auto v : test)
{
for(int i=0;i<3;i++)
cout << v[i];
cout << "\n";
}
}
该程序在遇到矢量的删除部分后给出了错误的输出。 Valgrind 说在尝试读取释放的内存时存在内存损坏。
怎么了?
向量元素必须 copy/move 可赋值,但您依赖默认的复制赋值运算符,它不会创建任何新内存。您分配的对象都共享相同的内存 space,稍后会导致双重释放。
你的构造函数很好,但你还需要一个 copy/move 赋值运算符。
了解 Rule of Five。
也可以考虑只使用 std::vector
作为后备存储;会简单很多。
Does delete[] work properly with generic arrays?
是的。
您的(隐式生成的)复制和移动赋值运算符是错误的。他们将复制成员指针。然后你有两个指向同一个数组的指针,一个析构函数删除它一次,另一个析构函数删除它第二次,这会导致未定义的行为。
手动管理动态资源时,必须跟踪所有权,并确保它恰好被释放一次。典型的解决方案是使用智能指针。您的 class 拥有动态数组的唯一所有权(或者,如果它没有意外地共享赋值运算符的所有权,它将拥有),因此唯一指针将是一个合适的选择。
另一方面,您可以使用向量容器而不是智能指针。
我试图使用圆形数组,因此最终编写了一个 CircularArray class,我已为其附加了代码。它使用数组的通用指针。 当我尝试使用 std::vector 创建此类圆形数组的列表时,我在尝试对其使用擦除时遇到问题。
我不明白为什么会这样,因为我认为析构函数和复制构造函数正常工作得很好。
有人可以帮忙吗?
代码:
循环数组 Class
template<class T> class CircularArray
{
//Class denoted by 'T' is expected to have a functional assignment operator, i.e. operator=(const T& ext) {} in place
protected:
int size=0;
int ori=0;
T* array;
private:
int pos=0;
public:
CircularArray() : CircularArray(0) {}
CircularArray(int s) {size=s;array=new T[s];}
CircularArray(T* ptr,int s)// : CircularArray(s)
{
size=s;array=new T[s];
for(int i=0;i<size;i++)
array[i]=ptr[i];
}
CircularArray(const CircularArray<T>& arr) : CircularArray(arr.size)
{
for(int i=0;i<size;i++)
array[i]=arr.array[i];
}
~CircularArray() {delete[] array;}
...
测试代码
int main()
{
std::vector<CircularArray<int>> test;
int *a1=new int[3] {1,2,3},*a2=new int[3] {1,2,3},*a3=new int[3] {1,2,3};
CircularArray<int> n1(a1,3),n2(a2,3),n3(a3,3);
test.push_back(n1);
test.push_back(n2);
test.push_back(n3);
test.erase(test.begin()+1);
for(auto v : test)
{
for(int i=0;i<3;i++)
cout << v[i];
cout << "\n";
}
}
该程序在遇到矢量的删除部分后给出了错误的输出。 Valgrind 说在尝试读取释放的内存时存在内存损坏。 怎么了?
向量元素必须 copy/move 可赋值,但您依赖默认的复制赋值运算符,它不会创建任何新内存。您分配的对象都共享相同的内存 space,稍后会导致双重释放。
你的构造函数很好,但你还需要一个 copy/move 赋值运算符。
了解 Rule of Five。
也可以考虑只使用 std::vector
作为后备存储;会简单很多。
Does delete[] work properly with generic arrays?
是的。
您的(隐式生成的)复制和移动赋值运算符是错误的。他们将复制成员指针。然后你有两个指向同一个数组的指针,一个析构函数删除它一次,另一个析构函数删除它第二次,这会导致未定义的行为。
手动管理动态资源时,必须跟踪所有权,并确保它恰好被释放一次。典型的解决方案是使用智能指针。您的 class 拥有动态数组的唯一所有权(或者,如果它没有意外地共享赋值运算符的所有权,它将拥有),因此唯一指针将是一个合适的选择。
另一方面,您可以使用向量容器而不是智能指针。