thi*_*ame 3 c++ arrays algorithm pointers
所以我有一个结构指针数组。它看起来像这样:
index [0 1 2 3 4]
value of structure 21 7 42 30 NULL
Run Code Online (Sandbox Code Playgroud)
我试图删除存储在索引 2 (42) 处的值。我以为既然这个数组的每个元素都是一个结构的指针,那么为了删除42,我必须先调用deletearr[2],然后我会说arr[2] = arr[3] 然后delete在 arr[3] 上,则 arr[3] = arr[4]。那是行不通的,所以我决定在没有delete关键字的情况下尝试它,只需执行 arr[2] = arr[3] 和 arr[3] = arr[4],它就成功了。所以我的问题是,为什么我不必使用delete关键字来执行此操作。我在想,如果我只是将 arr[2] 设置为 arr[3],那么 arr[2] 指向的结构就会丢失,并且会出现内存泄漏。不是这样吗?
我以为既然这个数组的每个元素都是一个指向结构的指针,那么为了删除42,我必须先在arr[2]上调用delete
是的,您将使用deleteonarr[2]以释放arr[2]指向的内存。
那么我会说 arr[2] = arr[3]
到现在为止还挺好。
然后在 arr[3] 上删除
这就是问题所在。假设你有这样的代码:
int arr_cnt = 5;
int *arr[arr_cnt];
for(int i = 0; i < arr_cnt; ++i)
arr[i] = new int(i+arr_cnt); // using ints for simplicity, but concept is the same
Run Code Online (Sandbox Code Playgroud)
你的数组arr现在看起来像这样:
idx *arr[] values in heap, due to using 'new' operator
+-----+
0 | a---|----> 5
+-----+
1 | b---|----> 6
+-----+
2 | c---|----> 7
+-----+
3 | d---|----> 8
+-----+
4 | e---|----> 9
+-----+
Run Code Online (Sandbox Code Playgroud)
其中字母代表new.返回的不同内存地址。
这意味着,要正确删除索引 2 处的元素,您需要:
deleteonarr[2]避免内存泄漏,arr[2]用其他一些仍然有效的地址覆盖(arr[2]在此步骤之前使用会触发段错误)arr[2](见下文)arr_cnt--;)换句话说:
delete arr[2]; // step 1, address 'c' no longer valid
arr[2] = arr[4]; // step 2, arr[2] is now 'e', which points to 9 just like arr[4]
arr[4] = NULL; // step 3, arr[4] is now invalid
--arr_cnt; // step 4
Run Code Online (Sandbox Code Playgroud)
该图现在看起来像这样:
idx *arr[] values in heap, due to using 'new' operator
+-----+
0 | a---|----> 5
+-----+
1 | b---|----> 6
+-----+
2 | e---|-----------+ // address 'e' used to be in arr[4]
+-----+ |
3 | d---|----> 8 |
+-----+ |
4 | nil | 9 <--+
+-----+
Run Code Online (Sandbox Code Playgroud)
然后 arr[3] = arr[4]。那不起作用
如果您按照图表进行操作,您现在可能已经注意到,同时使用delete两者意味着您使两个条目无效。换句话说,如果我们跳过第二个图表并尝试你的delete arr[2]; arr[2] = arr[3]; delete arr[3]逻辑,你最终会得到:
delete arr[2];
+-----+
0 | a---|----> 5
+-----+
1 | b---|----> 6
+-----+
2 | c---|----> ? // invalidated
+-----+
3 | d---|----> 8
+-----+
4 | e---|----> 9
+-----+
arr[2] = arr[3];
+-----+
0 | a---|----> 5
+-----+
1 | b---|----> 6
+-----+
2 | d---|-+
+-----+ |
3 | d---|-+--> 8 // both have the same address, so point to the same place
+-----+
4 | e---|----> 9
+-----+
delete arr[3];
+-----+
0 | a---|----> 5
+-----+
1 | b---|----> 6
+-----+
2 | d---|-+
+-----+ |
3 | d---|-+--> ? // both invalid now, but not set to null
+-----+
4 | e---|----> 9
+-----+
Run Code Online (Sandbox Code Playgroud)
所以我决定在没有 delete 关键字的情况下尝试它,只执行 arr[2] = arr[3] 和 arr[3] = arr[4],它奏效了。
但是现在你有内存泄漏。你总是要delete每一个new在C ++中,就像你总是有free每个malloc在C.
所以我的问题是,为什么我不必使用 delete 关键字来执行此操作。
你也必须使用它。问题是您使无效的次数比您想象的要多,并最终尝试使用已释放的内存。当程序尝试像这样访问内存时,会导致分段错误。我不记得 Windows 将显示的确切消息,但它可能是某种未处理的异常消息。(分段错误往往是 GNU/Linux 术语。)
我在想,如果我只是将 arr[2] 设置为 arr[3],那么 arr[2] 指向的结构就会丢失,并且会出现内存泄漏。不是这样吗?
你在这里是对的。问题不在于您对new/delete关系的理解,而在于您描述的分配是浅拷贝,并且您最终删除的内容超出预期。
| 归档时间: |
|
| 查看次数: |
7810 次 |
| 最近记录: |