在不改变索引顺序的情况下从动态数组中删除元素

Removing elements from dynamic arrays without changing the index order

本文关键字:数组 动态 删除 元素 情况下 改变 索引 顺序      更新时间:2023-10-16

我一直在尝试从数组中删除一个元素而不改变索引顺序,例如:

class MyObject  
{  
    int id;  
public:  
    MyObject() { }  
    void setId( int i ) { id = i; }  
    void showId() { std::cout << "ID: "<< id << "n"; }
};  
MyObject *myArray;
int main ( )  
{  
    myArray = new myArray[6];  
    for( int i = 0; i < 6; i++ )  
    {  
        myArray[i]->setId(i); 
        myArray[i]->showId();
    }  
}  

我想在不改变其他索引的情况下删除myArray[3]。例句:

myArray[0] = ID: 1  
myArray[1] = ID: 2  
myArray[2] = nothing  
myArray[3] = ID: 4  
myArray[4] = ID: 5  
myArray[5] = ID: 6    

我试着使用use memset(),但它没有工作。

memset(&myArray[3],0,sizeof(MyObject));

在c++语言中没有"nothing"这回事。一旦你有了一个数组,该数组的所有元素将包含"某物"。没有办法让一个数组元素只消失而保留所有其他元素在原来的位置。你不能在数组中创建一个洞。

在这种情况下,您所能做的就是简单地将某些元素标记为"已删除",然后再识别它。当然,元素将继续以物理形式存在。您将不得不将其识别为"已删除",并在进一步处理中忽略它。您可以添加一些bool is_deleted字段到您的对象,或者您可以使用id的一些保留值(如-1)来表示删除的元素。

memset的示例中,您实际上将id设置为零。0是有效的id值吗?如果不是,那么0是标记已删除元素的好选择。从这个意义上说,您的memset尝试工作得非常好,就像它应该的那样。虽然我建议通过显式地将0赋值给id,而不使用memset

您正在调用memset在对象实例的顶部写一堆零。不要这样做!如果你的课是一个真正的POD类,你可能会侥幸逃脱。最后可能会将ID设置为0。但也许你的班级还有更多你没有展示出来的东西。在任何情况下,即使不是POD,也不要那样使用memset

既可以存储指向object的指针,也可以使用空指针表示没有对象。我会用std::vector<MyObject*>这样做。或者使用哨兵对象实例,例如ID为-1的实例。

另一件可能出现问题的事情是,您似乎正在使用基于1的索引。c++数组是基于0的,所以第一个元素是myArray[0]而不是myArray[1]

以这种方式使用memset将该对象的所有字节设置为0。这通常相当于将id设置为0,因为对象的内存是其成员的内存(不包括虚表、填充等)。但无论如何都不要这样做。

一种方法是使用new并拥有一个指针数组。

MyObject* myArray[6];
int main ( )  
{ 
    for( int i = 0; i < 6; i++ )  
    {
        myArray[i] = new MyObject;
        myArray[i]->setId(i); 
        myArray[i]->showId();
    }  
}

然后显示它们:

for (int i = 0; i < 6; i++) {
    cout << "myArray[" << i << "] = ";
    if (myArray[i])
        myArray[i]->showId();
    else
        cout << "nothing" << endl;
}

然后当你想要删除一个对象时,delete它并设置它的指针为NULL:

delete myArray
myArray[3] = NULL;

当你对myArray中的一个对象做任何事情时,你必须检查它是否为NULL,以查看它是否是一个有效的对象。

考虑boost::optional:

typedef boost::optional<MyObject> MyObjectOpt;
MyObjectOptArr *myArray;

语法/用法有点不同(类似于使用指针):

for (int i = 0; i < 6; ++i) {      
    if (myArray[i])
        cout << "myArray[" << i << "] = " << *(myArray[N]);
    else
        cout << "nothing" << endl;
}

取消设置值do:

myArray[N] = boost::none;