【问题标题】:Deleting an dynamic array causes a runtime error删除动态数组会导致运行时错误
【发布时间】:2020-01-04 10:25:53
【问题描述】:

好的,所以我有这个关于 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;
}

【问题讨论】:

  • 你为什么要使用原始数组和指针? containersdynamic memory management 可用于标准 c++。
  • Dodaj 中,创建一个数组并将其指针存储在temp1 中,然后分配成员指针_elementi1 指向同一个数组,然后立即删除您创建的数组(这使得 _elementi1 成为悬空指针)。
  • @πάνταῥεῖ,正如我所说,这是一个家庭作业问题,我们必须纠正给定的程序才能工作。因此,我们必须使用原始指针。
  • @JFKay 恕我直言,你的老师教 c++ 的方式是错误的。
  • @Yksisarvinen 我不太明白。我不必删除指针位置的空间并将新空间分配给它,这样我就不会出现内存泄漏。你能提供一个关于你会怎么做的sn-p吗?我将不胜感激。我也更新了代码

标签: c++ class pointers templates


【解决方案1】:

首先,让我推荐你a good C++ book。 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_p2my_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

【讨论】:

  • 感谢您的详细解释,非常感谢!
  • 我还没有分配 _elementi1 的 temp1[i] = _elementi1[i] 值而不是地址?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-31
  • 2020-06-09
  • 2020-11-28
  • 2011-01-29
  • 1970-01-01
  • 2020-07-09
相关资源
最近更新 更多