使用memcpy将std::vector复制到protobuf中的重复字段

Copy a std::vector to a repeated field from protobuf with memcpy

本文关键字:字段 protobuf 复制 memcpy std vector 使用      更新时间:2023-10-16

首先我有一个简单的protobuf文件

message messagetest
{
    ...
    repeated float samples = 6;
    ....
}

它用这种方法创建了一个头文件

    //repeated float samples = 6;
      inline int samples_size() const;
      inline void clear_samples();
      static const int kSamplesFieldNumber = 6;
      inline float samples(int index) const;
      inline void set_samples(int index, float value);
      inline void add_samples(float value);
      inline const ::google::protobuf::RepeatedField< float >&  samples() const;
      inline ::google::protobuf::RepeatedField< float >* mutable_samples();

我基本上要做的是在for循环中一个接一个地复制所有数据。

int main(int argc, char** argv)
{    
    messagetest fMessage;
    
    vector<float> fData (1000, 0);
    // Create 1000 random values
    for (int i = 0; i < fData.size(); i++)
    {
        fData[i] = rand() % 1001;
    }
    
    for (int j = 0; j < fData.size(); j++)
    {
        fMessage.add_samples(fData[j]);    
    }
    return 0;
}

但我想使用类似memcpy的方法来加速复制过程。这只是我想到的一个想法。如果完全错误,请纠正我。头文件中的最后一个声明是:

inline ::google::protobuf::RepeatedField< float >* mutable_samples();

我不知道这种方法的作用(缺乏技巧(。但它看起来有点像矢量。也许这就是解决我问题的办法。如果是这样的话,我不知道如何实现它。

因为这还没有出现,而且我喜欢一行代码:

*fMessage.mutable_samples() = {fData.begin(), fData.end()};

我找到了将矢量复制到重复字段的最短方法,如下所示:

google::protobuf::RepeatedField<float> data(fData.begin(), fData.end());
fMessage.mutable_samples()->Swap(&data);

它可能也比您的更快,因为它避免了初始迭代并将值设置为0。

@mgild的答案将隐式调用RepeatedField(Iter begin, Iter end)构造函数来创建一个要移动分配的临时构造函数。与@nazgul的答案相同,显式创建一个临时RepeatedField并交换它。

更简单的是,避免创建新对象的方法是:

fMessage.mutable_samples()->Add(fData.begin(), fData.end())

如果samples字段尚未为空,则可以先调用Clear方法。

在内部,它使用std::copy(只要fData是一个前向迭代器(,所以它的速度将与您提出的任何memcpy实现一样快。

作为@mgild发布的优秀答案的替代方案,Assign也可以在这种情况下使用,因此数据在移动之前不会被复制到临时位置。

fMessage.mutable_samples()->Assign(fData.begin(), fData.end())

归功于Marek R的回答

fMessage.mutable_samples()

返回样本的指针数组:[*sample1,*sample2,sample3,…].

&fData[0]

是fData的第一个元素的地址。

memcpy(fMessage.mutable_samples()->mutable_data(),
     &fData[0],
     sizeof(float)*fData.size());

所以我认为上面的代码不能成功地将数据从fData填充到fMessage。这完全错了!