我现在正在学习 C++,之前是 Java。我确实知道我应该使用
vector
而不是数组,但是我也想了解基础知识。
我已经编写了一个结构,我想用双
[]
访问它。这确实有效并且达到了它的目的。但是,当调用析构函数时,我收到错误:
free(): invalid pointer
Aborted (core dumped)
我问了朋友,他也帮不了我。
这是结构:
#pragma once
class BitArray2
{
public:
int size;
BitArray2();
BitArray2(int size);
~BitArray2();
bool** bits = nullptr;
struct Row{
public:
int size;
bool** bits_row = nullptr;
int index;
Row(int size, int index, bool** bits_row)
:size(size), index(index), bits_row(bits_row){}
~Row(){
bits_row = nullptr;
}
bool& operator[](int col_index);
};
Row** rows = nullptr;
Row& operator[](int row_index);
};
BitArray2::BitArray2(){
BitArray2(1);
}
BitArray2::BitArray2(int size)
:size(size){
bits = new bool*[size];
rows = new Row*[size];
for (int i = 0; i < size; i++)
{
rows[i] = new Row(size, i, bits);
bits[i] = new bool[size];
}
}
BitArray2::~BitArray2(){
for (int i = 0; i < size; i++)
{
delete[] rows[i];
}
for (int i = 0; i < size; i++)
{
delete[] bits[i];
}
delete[] rows;
delete[] bits;
}
bool& BitArray2::Row::operator[](const int col_index)
{
if(col_index < size){
return bits_row[index][col_index];
}
else{
return bits_row[0][0];
}
}
BitArray2::Row& BitArray2::operator[](int row_index)
{
if(row_index < size){
return *rows[row_index];
}
else{
return *rows[0];
}
}
我还将给您一个示例应用程序:
BitArray2 b(4);
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
b[i][j] = (j+i)%2 == 0?true:false;
}
}
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if(b[i][j]){
std::cout << 1;
}else{
std::cout << 0;
}
}
std::cout << std::endl;
}
输出:
1010
0101
1010
0101
free(): invalid pointer
Aborted (core dumped)
所以我猜测,我的析构函数不正确。在我看来,我在某个地方尝试删除一个之前已经被不同的析构函数删除的对象。我首先删除了
rows
,它保存了对 bits
指针的引用,我将指针设置为 nullptr
,我命令析构函数不要删除顶部 bits
指针数组。也许这不起作用,因为 rows
结构体中的指针与一般 BitArray2
结构体中的指针相同。
我希望获得有关问题所在的更多信息,或者我可以研究一些来源以了解我遇到的问题。
大部分问题都在评论中指出:
BitArray2
班需要使用“三规则”或“五规则”。main
。delete[]
而不是 delete
。下面的代码中标记了修复程序,并提供了一些额外详细信息的注释。寻找
#if FIX_BY_TBXFREEWARE == 1
。
我还发现了一些其他需要修复的事情:
size
为零时,下标运算符将失败。通过在构造函数中添加检查来修复。
operator=
时,我都会自动编码一个
const
版本来配合它。我已经在这里做到了。
Row
不需要析构函数。它不使用运算符
new
。因此,不应该使用运算符
delete
。这是一个“零规则”结构。
bits
和
rows
,但我没有在这个问题上思考太久。@PaulMcKenzie 链接到一个
杰出示例,该示例展示了如何正确编码动态分配的二维数组。他的代码值得研究。
// BitArray2.h
#pragma once
#define FIX_BY_TBXFREEWARE 1
class BitArray2
{
public:
int size;
BitArray2();
BitArray2(int size);
~BitArray2();
#if FIX_BY_TBXFREEWARE == 1
// Class BitArray2 follows the "Rule of Three",
// or, possibly, the "Rule of Five". Either way,
// I have deleted the copy constructor and
// copy-assignment operator, so that they cannot
// be invoked. If you need them, you will need to
// code "deep-copy" versions of each.
BitArray2(BitArray2 const&) = delete;
BitArray2& operator=(BitArray2 const&) = delete;
#endif
bool** bits = nullptr;
struct Row {
public:
int size;
bool** bits_row = nullptr;
int index;
Row(int size, int index, bool** bits_row)
: size(size), index(index), bits_row(bits_row)
{}
#if FIX_BY_TBXFREEWARE == 1
// Struct Row follows the "Rule of Zero".
// Nothing was allocated with operator new,
// so nothing gets deleted.
#else
~Row() {
bits_row = nullptr;
}
#endif
bool& operator[](int col_index);
#if FIX_BY_TBXFREEWARE == 1
// Support for constant objects
bool const& operator[](int col_index) const;
#endif
};
Row** rows = nullptr;
Row& operator[](int row_index);
#if FIX_BY_TBXFREEWARE == 1
// Support for constant objects
Row const& operator[](int row_index) const;
#endif
};
// end file: BitArray2.h
// BitArray2.cpp
#include <stdexcept>
#include "BitArray2.h"
#if FIX_BY_TBXFREEWARE == 1
// Fix delegating constructor.
BitArray2::BitArray2()
: BitArray2(1)
{}
#else
BitArray2::BitArray2() {
BitArray2(1);
}
#endif
BitArray2::BitArray2(int size)
: size(size)
{
#if FIX_BY_TBXFREEWARE == 1
// The implementation of operator[] requires a non-zero size.
if (size < 1)
throw std::invalid_argument("Invalid size");
// Possible memory leak
// If the ctor fails, and throws std::bad_alloc,
// the dtor will NOT be called. When that happens,
// any allocations that DID WORK need to be deleted
// here. I have not coded a fix for this.
#endif
bits = new bool* [size];
rows = new Row * [size];
for (int i = 0; i < size; i++)
{
rows[i] = new Row(size, i, bits);
bits[i] = new bool[size];
}
}
BitArray2::~BitArray2() {
#if FIX_BY_TBXFREEWARE == 1
// Changed `delete[]` to `delete`.
for (int i = 0; i < size; i++)
{
delete rows[i];
delete bits[i];
}
#else
for (int i = 0; i < size; i++)
{
delete[] rows[i];
}
for (int i = 0; i < size; i++)
{
delete[] bits[i];
}
#endif
delete[] rows;
delete[] bits;
}
bool& BitArray2::Row::operator[](const int col_index)
{
if (col_index < size) {
return bits_row[index][col_index];
}
else {
return bits_row[0][0];
}
}
#if FIX_BY_TBXFREEWARE == 1
// Support for constant objects
bool const&
BitArray2::Row::operator[](const int col_index) const
{
if (col_index < size) {
return bits_row[index][col_index];
}
else {
return bits_row[0][0];
}
}
#endif
BitArray2::Row& BitArray2::operator[](int row_index)
{
if (row_index < size) {
return *rows[row_index];
}
else {
return *rows[0];
}
}
#if FIX_BY_TBXFREEWARE == 1
// Support for constant objects
BitArray2::Row const&
BitArray2::operator[](int row_index) const
{
if (row_index < size) {
return *rows[row_index];
}
else {
return *rows[0];
}
}
#endif
// end file: BitArray2.cpp
// main.cpp
#include <iostream>
#include "BitArray2.h"
int main()
{
BitArray2 b(4);
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
b[i][j] = (j + i) % 2 == 0 ? true : false;
}
}
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (b[i][j]) {
std::cout << 1;
}
else {
std::cout << 0;
}
}
std::cout << std::endl;
}
}
// end file: main.cpp
输出:
1010
0101
1010
0101