使用析构函数的问题
Trouble with destructor using
我开始学习c++,我运行陷入了这个问题。如果我不使用析构函数,那么一切正常,但是当我添加它时,会出现以下错误:
*** Error in `./arraylist.o': double free or corruption (fasttop): 0xb71ab360 ***
./test_arraylist.sh: line 2: 513 Aborted ./arraylist.o
我的源代码:
#include <iostream>
#include "jppsys.h"
namespace jpparl {
template <class T> class ArrayList {
private:
T *array;
int step;
long totalSize;
long usedSize = 0;
public:
ArrayList(long step) {
this->step = step;
totalSize = step;
array = new T[step];
std::cout << "\nCreate " << array << "\n";
}
ArrayList() {
this->step = 8;
totalSize = step;
array = new T[step];
std::cout << "\nCreate " << array << "\n";
}
ArrayList(const ArrayList &arraylist) {
step = arraylist.step;
totalSize = arraylist.totalSize;
usedSize = arraylist.usedSize;
array = new T[totalSize];
std::copy(arraylist.array, arraylist.array + totalSize, array);
std::cout << "\nCopy " << array << "\n";
}
~ArrayList() {
std::cout << "\nDelete " << array << "\n";
// delete[] array;
// ^^^^^^^^^^^^^^^ error here
}
void add(T elem, long index) {
if (usedSize == totalSize) totalSize += step;
T *tmp = new T[totalSize];
std::copy(array, array + index, tmp);
std::copy(array + index, array + index + usedSize, tmp + index + 1);
delete[] array;
tmp[index] = elem;
array = tmp;
usedSize++;
}
void remove(long index) {
if (usedSize == totalSize - step) totalSize -= step;
T *tmp = new T[totalSize];
std::copy(array, array + index, tmp);
std::copy(array + index + 1, array + usedSize, tmp + index);
delete[] array;
array = tmp;
usedSize--;
}
T get(long index) {
return array[index];
}
long size() {
return usedSize;
}
long getTotalSize() {
return totalSize;
}
};
}
using namespace jpparl;
using namespace std;
int main() {
ArrayList<ArrayList<int>> al(1);
ArrayList<int> al2(1);
cout << "\nAdding 256\n";
al2.add(256,0); // al2.get(0) - 256
cout << "\nAdding al2\n";
al.add(al2, 0); // adds copy of a2, al.get(0) - copy of.a2
cout << "\nRemoving 256\n";
al2.remove(0); // removes 256 from al2, not from a1
cout << al2.get(0) << " - must be 0 " << al.get(0).get(0) << " - must be 256\n";
cout << al2.size() << " - must be 0 " << al.get(0).size() << " - must be 1\n";
}
程序输出:
没有析构函数:
Create 0xb86d4f30
Create 0xb86d4f18
Create 0xb86d5360
Adding 256
Adding al2
Copy 0xb86d5360
Create 0xb86d53a0
Delete 0xb86d4f30
Delete 0xb86d5360
Removing 256
0 - must be 0
Copy 0xb86d5370
256 - must be 256
Delete 0xb86d5370
0 - must be 0
Copy 0xb86d53d8
1 - must be 1
Delete 0xb86d53d8
Delete 0xb86d53c8
Delete 0xb86d5388
带有析构函数:
Create 0xb71aaf30
Create 0xb71aaf18
Create 0xb71ab360
Adding 256
Adding al2
Copy 0xb71ab360
Create 0xb71ab3a0
Delete 0xb71aaf30
Delete 0xb71ab360
Removing 256
0 - must be 0
Copy 0xb71ab370
0 - must be 256
Delete 0xb71ab370
0 - must be 0
Copy 0xb71ab370
1 - must be 1
Delete 0xb71ab370
Delete 0xb71ab360
Delete 0xb71ab388
Delete 0xb71ab360
*** Error in `./arraylist.o': double free or corruption (fasttop): 0xb71ab360 ***
./test_arraylist.sh: line 2: 513 Aborted ./arraylist.o
我将不胜感激
正如Neil Butterworth所说,我需要添加一个赋值运算符。
#include <iostream>
namespace jpparl {
template <class T> class ArrayList {
private:
T *array;
int step;
long totalSize;
long usedSize = 0;
void copy(const ArrayList &arraylist) {
step = arraylist.step;
totalSize = arraylist.totalSize;
usedSize = arraylist.usedSize;
array = new T[totalSize];
std::copy(arraylist.array, arraylist.array + totalSize, array);
std::cout << "\nCopy " << array << "\n";
}
public:
ArrayList(long step) {
this->step = step;
totalSize = step;
array = new T[step];
std::cout << "\nCreate " << array << "\n";
}
ArrayList() {
this->step = 8;
totalSize = step;
array = new T[step];
std::cout << "\nCreate " << array << "\n";
}
ArrayList(const ArrayList &arraylist) {
copy(arraylist);
}
~ArrayList() {
std::cout << "\nDelete " << array << "\n";
delete[] array;
}
ArrayList& operator = (const ArrayList &arraylist) {
copy(arraylist);
}
void add(T elem, long index) {
if (usedSize == totalSize) totalSize += step;
T *tmp = new T[totalSize];
std::copy(array, array + index, tmp);
std::copy(array + index, array + index + usedSize, tmp + index + 1);
delete[] array;
tmp[index] = elem;
array = tmp;
usedSize++;
}
void remove(long index) {
if (usedSize == totalSize - step) totalSize -= step;
T *tmp = new T[totalSize];
std::copy(array, array + index, tmp);
std::copy(array + index + 1, array + usedSize, tmp + index);
delete[] array;
array = tmp;
usedSize--;
}
T get(long index) {
return array[index];
}
long size() {
return usedSize;
}
long getTotalSize() {
return totalSize;
}
};
}
using namespace jpparl;
using namespace std;
int main() {
ArrayList<ArrayList<int>> al(1);
ArrayList<int> al2(1);
cout << "\nAdding 256\n";
al2.add(256,0); // al2.get(0) - 256
cout << "\nAdding al2\n";
al.add(al2, 0); // adds copy of a2, al.get(0) - copy of.a2
cout << "\nRemoving 256\n";
al2.remove(0); // removes 256 from al2, not from a1
cout << al2.get(0) << " - must be 0 " << al.get(0).get(0) << " - must be 256\n";
cout << al2.size() << " - must be 0 " << al.get(0).size() << " - must be 1\n";
}
缺少赋值运算符。在行
al.add(al2, 0);
al2是浅拷贝,意思是两个对象共享同一个buffer。然后它被删除两次。一次是在传递给 add 方法的临时对象被销毁之后,一次是在主函数结束时。
你的 class 不遵循 Rule of 3,这基本上表明如果 class 需要实现复制构造函数、复制赋值运算符或析构函数,它可能需要实现所有这三个(C++11 通过添加移动构造函数和移动赋值运算符引入移动语义,从而制定 5 规则)。
你的 class 有一个复制构造函数和一个析构函数,但它缺少一个复制赋值运算符,当复制本身是你的 [=33= 实例的元素时,std::copy()
会调用它].您的 class 还缺少移动构造函数和移动赋值运算符,因为您使用的是 C++11(通过虚拟初始化 usedSize
成员的方式)。
此外,您的 add()
和 remove()
方法也没有正确管理数组。无需在每次 add/remove 操作时重新分配数组。这违背了 step
会员的全部目的。仅在实际需要时重新分配(growing/shrinking 超出当前 step
)。
在这种情况下最好的选择是简单地使用 std::vector
而不是手动数组,例如:
#include <vector>
#include <utility>
#include "jppsys.h"
namespace jpparl {
template <class T>
class ArrayList {
private:
std::vector<T> array;
public:
void add(const T &elem) {
array.push_back(elem);
}
void add(const T &elem, long index) {
array.insert(array.begin()+index, std::move(elem));
}
void remove(long index) {
array.erase(array.begin()+index);
}
T get(long index) {
return array[index];
}
long size() {
return array.size();
}
long getTotalSize() {
return array.capacity();
}
};
}
如果这不是您的选择,如果您必须使用手动数组,那么您应该在复制数组时使用 copy-swap idiom,例如:
#include <algorithm>
#include <utility>
#include "jppsys.h"
namespace jpparl {
template <class T>
class ArrayList {
private:
T *array;
int step;
long totalSize;
long usedSize = 0;
public:
ArrayList(long step = 8) {
this->step = step;
totalSize = step;
array = new T[totalSize];
}
ArrayList(const ArrayList &src) {
step = src.step;
totalSize = src.totalSize;
usedSize = src.usedSize;
array = new T[totalSize];
std::copy(src.array, src.array + usedSize, array);
}
ArrayList(ArrayList &&src) {
step = src.step;
totalSize = 0;
usedSize = 0;
array = nullptr;
src.swap(*this);
}
~ArrayList() {
delete[] array;
}
ArrayList& operator=(const ArrayList &rhs) {
if (&rhs != this)
ArrayList(rhs).swap(*this);
return *this;
}
ArrayList& operator=(ArrayList &&rhs) {
rhs.swap(*this);
return *this;
}
void swap(ArrayList &other) {
std::swap(step, other.step);
std::swap(totalSize, other.totalSize);
std::swap(usedSize, other.usedSize);
std::swap(array, other.array);
}
void add(const T &elem, long index = -1) {
if (index == -1) index = usedSize;
if (usedSize == totalSize) {
ArrayList tmp(totalSize + step);
std::copy(array, array + usedSize, tmp.array);
std::swap(array, tmp.array);
totalSize = tmp.totalSize;
}
std::copy_backward(array + index, array + index + (usedSize - index), array + usedSize + 1);
array[index] = elem;
++usedSize;
}
void remove(long index) {
std::copy(array + index + 1, array + usedSize, array + index);
--usedSize;
if ((usedSize == (totalSize - step)) && (totalSize > step)) {
ArrayList tmp(totalSize - step);
std::copy(array, array + usedSize, tmp.array);
std::swap(array, tmp.array);
totalSize = tmp.totalSize;
}
}
T get(long index) {
return array[index];
}
long size() {
return usedSize;
}
long getTotalSize() {
return totalSize;
}
};
}
我开始学习c++,我运行陷入了这个问题。如果我不使用析构函数,那么一切正常,但是当我添加它时,会出现以下错误:
*** Error in `./arraylist.o': double free or corruption (fasttop): 0xb71ab360 ***
./test_arraylist.sh: line 2: 513 Aborted ./arraylist.o
我的源代码:
#include <iostream>
#include "jppsys.h"
namespace jpparl {
template <class T> class ArrayList {
private:
T *array;
int step;
long totalSize;
long usedSize = 0;
public:
ArrayList(long step) {
this->step = step;
totalSize = step;
array = new T[step];
std::cout << "\nCreate " << array << "\n";
}
ArrayList() {
this->step = 8;
totalSize = step;
array = new T[step];
std::cout << "\nCreate " << array << "\n";
}
ArrayList(const ArrayList &arraylist) {
step = arraylist.step;
totalSize = arraylist.totalSize;
usedSize = arraylist.usedSize;
array = new T[totalSize];
std::copy(arraylist.array, arraylist.array + totalSize, array);
std::cout << "\nCopy " << array << "\n";
}
~ArrayList() {
std::cout << "\nDelete " << array << "\n";
// delete[] array;
// ^^^^^^^^^^^^^^^ error here
}
void add(T elem, long index) {
if (usedSize == totalSize) totalSize += step;
T *tmp = new T[totalSize];
std::copy(array, array + index, tmp);
std::copy(array + index, array + index + usedSize, tmp + index + 1);
delete[] array;
tmp[index] = elem;
array = tmp;
usedSize++;
}
void remove(long index) {
if (usedSize == totalSize - step) totalSize -= step;
T *tmp = new T[totalSize];
std::copy(array, array + index, tmp);
std::copy(array + index + 1, array + usedSize, tmp + index);
delete[] array;
array = tmp;
usedSize--;
}
T get(long index) {
return array[index];
}
long size() {
return usedSize;
}
long getTotalSize() {
return totalSize;
}
};
}
using namespace jpparl;
using namespace std;
int main() {
ArrayList<ArrayList<int>> al(1);
ArrayList<int> al2(1);
cout << "\nAdding 256\n";
al2.add(256,0); // al2.get(0) - 256
cout << "\nAdding al2\n";
al.add(al2, 0); // adds copy of a2, al.get(0) - copy of.a2
cout << "\nRemoving 256\n";
al2.remove(0); // removes 256 from al2, not from a1
cout << al2.get(0) << " - must be 0 " << al.get(0).get(0) << " - must be 256\n";
cout << al2.size() << " - must be 0 " << al.get(0).size() << " - must be 1\n";
}
程序输出:
没有析构函数:
Create 0xb86d4f30
Create 0xb86d4f18
Create 0xb86d5360
Adding 256
Adding al2
Copy 0xb86d5360
Create 0xb86d53a0
Delete 0xb86d4f30
Delete 0xb86d5360
Removing 256
0 - must be 0
Copy 0xb86d5370
256 - must be 256
Delete 0xb86d5370
0 - must be 0
Copy 0xb86d53d8
1 - must be 1
Delete 0xb86d53d8
Delete 0xb86d53c8
Delete 0xb86d5388
带有析构函数:
Create 0xb71aaf30
Create 0xb71aaf18
Create 0xb71ab360
Adding 256
Adding al2
Copy 0xb71ab360
Create 0xb71ab3a0
Delete 0xb71aaf30
Delete 0xb71ab360
Removing 256
0 - must be 0
Copy 0xb71ab370
0 - must be 256
Delete 0xb71ab370
0 - must be 0
Copy 0xb71ab370
1 - must be 1
Delete 0xb71ab370
Delete 0xb71ab360
Delete 0xb71ab388
Delete 0xb71ab360
*** Error in `./arraylist.o': double free or corruption (fasttop): 0xb71ab360 ***
./test_arraylist.sh: line 2: 513 Aborted ./arraylist.o
我将不胜感激
正如Neil Butterworth所说,我需要添加一个赋值运算符。
#include <iostream>
namespace jpparl {
template <class T> class ArrayList {
private:
T *array;
int step;
long totalSize;
long usedSize = 0;
void copy(const ArrayList &arraylist) {
step = arraylist.step;
totalSize = arraylist.totalSize;
usedSize = arraylist.usedSize;
array = new T[totalSize];
std::copy(arraylist.array, arraylist.array + totalSize, array);
std::cout << "\nCopy " << array << "\n";
}
public:
ArrayList(long step) {
this->step = step;
totalSize = step;
array = new T[step];
std::cout << "\nCreate " << array << "\n";
}
ArrayList() {
this->step = 8;
totalSize = step;
array = new T[step];
std::cout << "\nCreate " << array << "\n";
}
ArrayList(const ArrayList &arraylist) {
copy(arraylist);
}
~ArrayList() {
std::cout << "\nDelete " << array << "\n";
delete[] array;
}
ArrayList& operator = (const ArrayList &arraylist) {
copy(arraylist);
}
void add(T elem, long index) {
if (usedSize == totalSize) totalSize += step;
T *tmp = new T[totalSize];
std::copy(array, array + index, tmp);
std::copy(array + index, array + index + usedSize, tmp + index + 1);
delete[] array;
tmp[index] = elem;
array = tmp;
usedSize++;
}
void remove(long index) {
if (usedSize == totalSize - step) totalSize -= step;
T *tmp = new T[totalSize];
std::copy(array, array + index, tmp);
std::copy(array + index + 1, array + usedSize, tmp + index);
delete[] array;
array = tmp;
usedSize--;
}
T get(long index) {
return array[index];
}
long size() {
return usedSize;
}
long getTotalSize() {
return totalSize;
}
};
}
using namespace jpparl;
using namespace std;
int main() {
ArrayList<ArrayList<int>> al(1);
ArrayList<int> al2(1);
cout << "\nAdding 256\n";
al2.add(256,0); // al2.get(0) - 256
cout << "\nAdding al2\n";
al.add(al2, 0); // adds copy of a2, al.get(0) - copy of.a2
cout << "\nRemoving 256\n";
al2.remove(0); // removes 256 from al2, not from a1
cout << al2.get(0) << " - must be 0 " << al.get(0).get(0) << " - must be 256\n";
cout << al2.size() << " - must be 0 " << al.get(0).size() << " - must be 1\n";
}
缺少赋值运算符。在行
al.add(al2, 0);
al2是浅拷贝,意思是两个对象共享同一个buffer。然后它被删除两次。一次是在传递给 add 方法的临时对象被销毁之后,一次是在主函数结束时。
你的 class 不遵循 Rule of 3,这基本上表明如果 class 需要实现复制构造函数、复制赋值运算符或析构函数,它可能需要实现所有这三个(C++11 通过添加移动构造函数和移动赋值运算符引入移动语义,从而制定 5 规则)。
你的 class 有一个复制构造函数和一个析构函数,但它缺少一个复制赋值运算符,当复制本身是你的 [=33= 实例的元素时,std::copy()
会调用它].您的 class 还缺少移动构造函数和移动赋值运算符,因为您使用的是 C++11(通过虚拟初始化 usedSize
成员的方式)。
此外,您的 add()
和 remove()
方法也没有正确管理数组。无需在每次 add/remove 操作时重新分配数组。这违背了 step
会员的全部目的。仅在实际需要时重新分配(growing/shrinking 超出当前 step
)。
在这种情况下最好的选择是简单地使用 std::vector
而不是手动数组,例如:
#include <vector>
#include <utility>
#include "jppsys.h"
namespace jpparl {
template <class T>
class ArrayList {
private:
std::vector<T> array;
public:
void add(const T &elem) {
array.push_back(elem);
}
void add(const T &elem, long index) {
array.insert(array.begin()+index, std::move(elem));
}
void remove(long index) {
array.erase(array.begin()+index);
}
T get(long index) {
return array[index];
}
long size() {
return array.size();
}
long getTotalSize() {
return array.capacity();
}
};
}
如果这不是您的选择,如果您必须使用手动数组,那么您应该在复制数组时使用 copy-swap idiom,例如:
#include <algorithm>
#include <utility>
#include "jppsys.h"
namespace jpparl {
template <class T>
class ArrayList {
private:
T *array;
int step;
long totalSize;
long usedSize = 0;
public:
ArrayList(long step = 8) {
this->step = step;
totalSize = step;
array = new T[totalSize];
}
ArrayList(const ArrayList &src) {
step = src.step;
totalSize = src.totalSize;
usedSize = src.usedSize;
array = new T[totalSize];
std::copy(src.array, src.array + usedSize, array);
}
ArrayList(ArrayList &&src) {
step = src.step;
totalSize = 0;
usedSize = 0;
array = nullptr;
src.swap(*this);
}
~ArrayList() {
delete[] array;
}
ArrayList& operator=(const ArrayList &rhs) {
if (&rhs != this)
ArrayList(rhs).swap(*this);
return *this;
}
ArrayList& operator=(ArrayList &&rhs) {
rhs.swap(*this);
return *this;
}
void swap(ArrayList &other) {
std::swap(step, other.step);
std::swap(totalSize, other.totalSize);
std::swap(usedSize, other.usedSize);
std::swap(array, other.array);
}
void add(const T &elem, long index = -1) {
if (index == -1) index = usedSize;
if (usedSize == totalSize) {
ArrayList tmp(totalSize + step);
std::copy(array, array + usedSize, tmp.array);
std::swap(array, tmp.array);
totalSize = tmp.totalSize;
}
std::copy_backward(array + index, array + index + (usedSize - index), array + usedSize + 1);
array[index] = elem;
++usedSize;
}
void remove(long index) {
std::copy(array + index + 1, array + usedSize, array + index);
--usedSize;
if ((usedSize == (totalSize - step)) && (totalSize > step)) {
ArrayList tmp(totalSize - step);
std::copy(array, array + usedSize, tmp.array);
std::swap(array, tmp.array);
totalSize = tmp.totalSize;
}
}
T get(long index) {
return array[index];
}
long size() {
return usedSize;
}
long getTotalSize() {
return totalSize;
}
};
}