所以我有一组结构指针。它看起来像这样:
index [0 1 2 3 4]
value of structure 21 7 42 30 NULL
我试图删除存储在索引2(42)的值。我认为,因为每个
这个数组的元素是一个指向结构的指针,然后为了删除42,
我必须首先在arr [2]上调用delete
,然后我会说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]指向的结构将丢失,我会得到内存泄漏。那不是这样吗?
答案 0 :(得分:2)
我认为既然这个数组的每个元素都是一个指向结构的指针,那么为了删除42,我必须首先在arr上调用delete [2]
是的,您可以在delete
上使用arr[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
您的数组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
+-----+
字母代表new
返回的不同内存地址。
这意味着,要正确删除索引2处的元素,您需要:
delete
上使用arr[2]
以避免内存泄漏,arr[2]
(在此步骤之前使用arr[2]
会触发seg-fault)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
图表现在看起来像这样:
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 <--+
+-----+
然后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
+-----+
所以我决定尝试不使用delete关键字,只需要执行arr [2] = arr [3]和arr [3] = arr [4],它就可以了。
但现在你有内存泄漏。您在C ++中每delete
总是new
,就像C中每free
malloc
一样。
所以我的问题是,为什么我不必使用delete关键字来执行此操作。
你做必须使用它。问题是你的失效比你想象的要多,最后还是尝试使用已经解除分配的内存。当程序试图访问这样的内存时,会导致分段错误。我不记得Windows会显示的确切消息,但它可能是某种未处理的异常消息。 (分段错误往往是GNU / Linux术语。)
我在想如果我只是将arr [2]设置为arr [3],那么arr [2]指向的结构就会丢失,我会得到内存泄漏。那不是这样吗?
你在这里是对的。问题不在于您对new
/ delete
关系的理解,而是您所描述的分配是浅副本这一事实,并且您最终删除的内容超出预期。< / p>
答案 1 :(得分:0)
检查以确保您确实拥有一组结构指针。此外,如果在删除索引2处的元素后确实有一个结构指针数组,请不要在3或之后的索引上调用delete。只是arr [2] = arr [3]; arr [3] = arr [4];它不是内存泄漏,因为您只是复制指向结构的指针而不是实际结构。
struct A
{
};
//This is an array of A structures
A * array1;
//This is an array of pointers to A structures
A** array2;
答案 2 :(得分:0)
我必须首先在arr [2]上调用delete,然后我会说arr [2] = arr [3]然后在arr [3]上删除,然后arr [3] = arr [4]。< / p>
您只需删除arr[2]
并将所有项目移至左侧,而不删除它们。如果您将delete
应用于所有后续对象,那么您将全部松开它们。
当然,您可以简单地移动数组而不删除arr[2]
,但这会导致内存泄漏。该物件不会被处置。
答案 3 :(得分:0)
您遇到的问题是删除了不应删除的指针。
在索引2处删除旧指针并将索引3分配给索引2后,您有两个指向同一对象的指针:在索引2和3处。删除指向的对象to by index 3删除两个指针指向的对象,使索引2中的指针无效。
问题的解决方案(除了切换到我推荐的std::vector
之外)是删除索引2中的第一个对象,向下移动较高索引的值(例如array[2] = array[3]
)和将最后一个指针设置为nullptr
。不再需要删除。
答案 4 :(得分:0)
最好的方法是使用链接列表。
请按照以下链接。
http://www.c4learn.com/data-structure/delete-node-from-first-postion-in-singly-linked-list/