关于c ++:如何删除重复字段中的任意对象? (protobuf)

How to delete arbitrary objects in repeated field? (protobuf)

我的原型中的重复字段中有一些条目。 现在我要删除其中一些。 我该怎么做? 有一个删除最后一个元素的功能,但是我想删除任意元素。 我不能只交换它们,因为顺序很重要。

我可以与下一个交换直到结束,但是没有更好的解决方案吗?


Protobuf v2

您可以在RepeatedPtrField类中使用DeleteSubrange(int start, int num)

如果要删除单个元素,则必须将此方法称为DeleteSubrange(index_to_be_del, 1)。 它将删除该索引处的元素。

Protobuf v3更新

如评论中所述,iterator RepeatedField::erase(const_iterator position)可以在任意位置删除


根据API文档,没有一种方法可以从重复字段中任意删除一个元素,而只是删除最后一个元素。

...
We don't provide a way to remove any element other than the last
because it invites inefficient use, such as O(n^2) filtering loops
that should have been O(n). If you want to remove an element other
than the last, the best way to do it is to re-arrange the elements so
that the one you want removed is at the end, then call RemoveLast()
...


在这些情况下,我通常要做的是创建新的Protobuf(PB)消息。 我迭代现有消息的重复字段,并将它们(除了您不再想要的字段除外)添加到新的PB消息中。


这是示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
message GuiChild
{
    optional string widgetName = 1;
    //..
}

message GuiLayout
{
    repeated ChildGuiElement children = 1;
    //..
}

typedef google_public::protobuf::RepeatedPtrField<GuiChild> RepeatedField;
typedef google_public::protobuf::Message Msg;

GuiLayout guiLayout;
//Init children as necessary..

GuiChild child;
//Set child fileds..

DeleteElementsFromRepeatedField(*child, guiLayout->mutable_children());

void DeleteElementsFromRepeatedField(const Msg& msg, RepeatedField* repeatedField)
{
    for (RepeatedField::iterator it = repeatedField->begin(); it != repeatedField->end(); it++)
    {
        if (google_public::protobuf::util::MessageDifferencer::Equals(*it, msg))
        {
            repeatedField->erase(it);
            break;
        }
    }
}


尽管没有简单的方法,您仍然可以执行此操作(对于使用反射的自定义消息)。 下面的代码删除从row索引开始的count重复字段项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void RemoveFromRepeatedField(
    const google::protobuf::Reflection *reflection,
    const google::protobuf::FieldDescriptor *field,
    google::protobuf::Message *message,
    int row,
    int count)
{
    int size = reflection->FieldSize(*message, field);
    // shift all remaining elements
    for (int i = row; i < size - count; ++i)
        reflection->SwapElements(message, field, i, i + count);
    // delete elements from reflection
    for (int i = 0; i < count; ++i)
        reflection->RemoveLast(message, field);
}