2015-11-04 208 views
0

所以我有一个结构指针数组。它看起来像这样:从指针数组中删除元素 - C++

index     [0 1 2 3 4] 
value of structure  21 7 42 30 NULL 

我试图删除存储在索引2(42)的值。我认为,因为这个数组的每个 元素都是一个指向结构体的指针,那么为了删除42, ,我必须先在arr [2]上调用delete,然后我会说arr [2] = arr [3 ] ,然后在arr [3]上使用delete,然后arr [3] = arr [4]。 这是不工作,所以我只是决定尝试没有delete关键字,只是做arr [2] = arr [3]和arr [3] = arr [4],它的工作。 所以我的问题是,为什么我不必使用delete关键字来做到这一点。我在想,如果我只是将arr [2]设置为arr [3],那么arr [2]指向的结构将会丢失,并且会导致内存泄漏。情况并非如此吗?

+0

改为使用'std :: vector'。从矢量中删除要删除的指针,然后[擦除](http://en.cppreference.com/w/cpp/container/vector/erase)。 –

+0

其实,我试图从学校学习一个概念,所以我需要这样做。 –

+0

请记住回来接受你认为对你最有帮助的答案。它有益于你,海报和整个社区。 – ray

回答

1

我认为,因为此数组中的每个元素是一个指针,指向的结构,则为了删除42,我必须先调用删除ARR [2]

是的,你将在arr[2]上使用delete以释放arr[2]指向的内存。

那么我会说ARR [2] = ARR [3]

到目前为止好。

,然后改编删除[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正常删除的元素,你需要:

  1. arr[2]使用delete,以避免内存泄漏,
  2. 覆盖arr[2]与这仍然有效一些其他的地址(使用arr[2]现在会触发段错误)
  3. 无效阵列位置复制到arr[2](见下文)
  4. 递减数组的长度(例如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 <--+ 
    +-----+ 

然后常用3 [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 
    +-----+ 

所以我决定尝试没有删除关键字,只是不常用3 [2] = ARR [3]和arr [3] = arr [4],并且工作。

但现在你有内存泄漏。你总是要deletenew在C++中,就像你总是要freemalloc在C.

所以我的问题是,为什么我没有使用delete关键字才能做到这一点。

必须使用它。问题在于你的失效比你想像的要多,最终试图与已被释放的内存一起工作。当程序尝试像这样访问内存时,会导致分段错误。我不记得Windows会显示的确切消息,但它可能是某种未处理的异常消息。 (分割错误往往是GNU/Linux术语。)

我在想,如果我只是将arr [2]设置为arr [3],那么arr [2]指向的结构将会丢失,我会得到一个内存泄漏。情况并非如此吗?

你在这里是正确的。问题不在于你对new/delete关系的理解,只是你描述的任务是副本,并且最终删除了超过预期的结果。

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; 
0

我必须先调用删除ARR [2],然后我会说ARR [2] = ARR [3],然后在ARR删除[3],则常用3 [3] = ARR [4]。

您需要简单地删除arr[2]和所有物品转移到左侧,而不删除它们。如果您将delete应用于所有相应的对象,则您将全部松开。

当然,您可以简单地移动数组而不删除arr[2],但这会导致内存泄漏。该物体不会被丢弃。

0

您遇到的问题是您删除了不应删除的指针。

后您删除索引2老指针,并分配在索引3索引2,你有指针指向同一个对象:和指向索引3索引2 3.删除对象删除两个指针指向的对象,使索引2中的指针无效。

的解决问题的方法(除了切换到std::vector这是我的建议)是删除索引2的第一个对象,该值从更高的指标(如array[2] = array[3])向下移动,最后指针设置为nullptr。不再需要删除。