首页 > 解决方案 > 删除动态数组会导致运行时错误

问题描述

好的,所以我有这个关于 c++ 的作业问题并删除了一个动态数组。当我运行该程序时,它向我显示以下内容:http: //prntscr.com/p015e9 我猜问题出在删除指针上,因为我将其追踪到这些行:

delete[] _elementi1; _elementi1 = nullptr;
delete[] _elementi2; _elementi2 = nullptr;

这是我的课,当我调用“Dodaj”函数时发生错误

template<class T1, class T2 = int>
class FITKolekcija {

    T1 * _elementi1;
    T2 * _elementi2;
    int _trenutno;

    public:
    FITKolekcija() {
        _elementi1 = nullptr; // Elements 1 pointer
        _elementi2 = nullptr; // Elements 2 pointer
        _trenutno = 0; // This is the _current variable and is used as an iterator
    }
    ~FITKolekcija() {
        try {
            delete[] _elementi1; _elementi1 = nullptr;
            delete[] _elementi2; _elementi2 = nullptr;
        }
        catch (exception& e) {

            cout << e.what() << endl;
        }
    }
    T1 * GetT1() { return _elementi1; }
    T2 * GetT2() { return _elementi2; }
    int GetTrenutno() { return _trenutno; }

    friend ostream& operator<< (ostream &COUT, FITKolekcija &obj) {
        for (size_t i = 0; i < obj._trenutno; i++)
            COUT << obj._elementi1[i] << " " << obj._elementi2[i] << endl;
        return COUT;
    }

    void Dodaj(T1 clan1, T2 clan2) {

        T1 *temp1 = new T1[_trenutno + 1];
        T2 *temp2 = new T2[_trenutno + 1];

        for (size_t i = 0; i < _trenutno; i++) {

            temp1[i] = _elementi1[i];
            temp2[i] = _elementi2[i];
        }

        delete[] _elementi1; _elementi1 = nullptr; // Here lies the runtime error
        delete[] _elementi2; _elementi2 = nullptr;

        temp1[_trenutno] = clan1;
        temp2[_trenutno] = clan2;

        _elementi1 = temp1;
        _elementi2 = temp2;

        _trenutno++;

    //
    }
}

使用以下代码,我可以在运行时错误发生之前执行 7 次“Dodaj”,如下所示:

int main() {
int v6 = 6, v13 = 13, v32 = 32, v63 = 63, v98 = 98, v109 = 109, v196 = 196;

FITKolekcija<int, int> numbers;

cout << "1" << endl;
numbers.Dodaj(v196, v6);
cout << "2" << endl;
numbers.Dodaj(v13, v32);
cout << "3" << endl;
numbers.Dodaj(v98, v196);
cout << "4" << endl;
numbers.Dodaj(v63, v13);
cout << "5" << endl;
numbers.Dodaj(v98, v196);
cout << "6" << endl;
numbers.Dodaj(v196, v6);
cout << "7" << endl;

return 0;
}

标签: c++classpointerstemplates

解决方案


首先,让我向您推荐一本好的 C++ 书籍。StackOverflow 不是学习基础知识的最佳场所。

指针是一个盒子。在这个盒子里,你可以放一张纸,上面写着一个地址。当你有一个指针时,它通常不与任何现有对象相关联(没有存储在框中的地址):

int my_p;

my_p
--------
| NULL |
--------

当您使用 时new,您可以在某处获得指向某个真实对象的指针(您在某处建造一座真实建筑物并写下它的地址)。

my_p = new int[5];

my_p
----------
| 0x2358 |
----------

 0x2358   0x2359   0x2360   0x2361   0x2362
-------- -------- -------- -------- -------- 
|   0  | |   0  | |   0  | |   0  | |   0  | 
-------- -------- -------- -------- -------- 

您可以随意编辑指针指向的对象(您知道地址,您可以去建筑物并在那里粉刷墙壁):

my_p[2] = 13;

my_p
----------
| 0x2358 |
----------

 0x2358   0x2359   0x2360   0x2361   0x2362
-------- -------- -------- -------- -------- 
|   0  | |   0  | |  13  | |   0  | |   0  | 
-------- -------- -------- -------- -------- 

现在,当你复制一个指针时,你只复制了一个指针,而不是它指向的对象(你得到一个新的盒子并将相同的地址放在这个盒子里):

int* my_p2 = my_p;

my_p       my_p2
---------- ----------
| 0x2358 | | 0x2358 | 
---------- ----------

 0x2358   0x2359   0x2360   0x2361   0x2362
-------- -------- -------- -------- -------- 
|   0  | |   0  | |  13  | |   0  | |   0  | 
-------- -------- -------- -------- -------- 

my_p2具有完全相同的属性my_p并且它指向完全相同的对象my_p(有任何一个盒子,你可以去房子并在那里放置地毯):

my_p2[3] = 26;

my_p
----------
| 0x2358 |
----------

 0x2358   0x2359   0x2360   0x2361   0x2362
-------- -------- -------- -------- -------- 
|   0  | |   0  | |  13  | |  26  | |   0  | 
-------- -------- -------- -------- -------- 
std::cout << my_p[3]; // prints 26, even though you used my_p2

当你delete成为一个对象时,它会被标记为免费供编译器再次使用。(您获取地址并摧毁该地址的建筑物)。请注意,您无法保证该内存中的内容 - 从现在开始,它绝对可以是任何东西。

delete[] my_p;

my_p       my_p2
---------- ----------
| 0x2358 | | 0x2358 | 
---------- ----------

 0x2358   0x2359   0x2360   0x2361   0x2362
-------- -------- -------- -------- -------- 
| FREE | | FREE | | FREE | | FREE | | FREE | 
-------- -------- -------- -------- -------- 

但是指针本身并没有改变!他们仍然指向记忆中的相同位置(你摧毁了房子,但盒子在其他地方仍然是安全的,没有人在这些盒子里装过任何东西)。
这就是我们所说的悬空指针。如果您现在尝试使用此类指针指向的对象,您会得到未定义的行为(您带来了油漆和画笔并去了给定的地址,但没有房子可以油漆,或者更糟糕的是 - 其他人已经在那里建造了他们的房子!)

std::cout << my_p2[2]; //can format your C drive if it wishes to do so

推荐阅读