Kopieren Sie einen std::vector in ein wiederholtes Feld von protobuf mit memcpy

Lesezeit: 4 Minuten

Benutzer-Avatar
akristmann

Zuerst habe ich diese einfache protobuf-Datei

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

Was mit diesen Methoden eine Headerdatei erstellt

    //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();

Was ich im Grunde tue, ist, alle Daten einzeln in eine for-Schleife zu kopieren.

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

Aber ich möchte eine Methode wie memcpy verwenden, um den Kopiervorgang zu beschleunigen. Es ist nur eine Idee, die mir in den Sinn kommt. Wenn es völlig falsch ist, korrigiere mich. Die letzte Deklaration in der Headerdatei lautet:

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

Ich habe keine Ahnung, was diese Methode bewirkt (Mangel an Geschick). Aber es sieht irgendwie aus wie ein Vektor. Vielleicht ist das die Lösung für mein Problem. Wenn ja, habe ich keine Ahnung, wie ich das umsetzen soll.

  • Haben Sie es profiliert und gesehen, dass es langsam ist? Haben Sie den kompilierten Code überprüft und festgestellt, dass er schlecht optimiert ist?

    – Nicht zu gebrauchen

    19. März 2013 um 13:23 Uhr

Da dies noch nicht hier ist und ich Einzeiler mag:

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

  • Beachten Sie, dass es mit c++11 und höher funktioniert, da die Neuzuweisung mithilfe der Initialisiererliste vor c++11 nicht verfügbar war.

    – Siddu

    3. Januar 2019 um 12:32 Uhr

  • Kopiert oder verschiebt diese Zuweisung den verwendeten Speicher?

    – Dávid Toth

    19. September 2019 um 8:18 Uhr

  • @DavidTóth kopiert den Bereich in ein temporäres und dann wird das temporäre Move dem wiederholten Feld pbf zugewiesen

    – Kevin Kreiser

    23. Oktober 2020 um 13:08 Uhr

  • @hamilyon en.cppreference.com/w/cpp/language/list_initialization

    – Gold

    29. Oktober 2020 um 4:06 Uhr

  • Beachten Sie, dass mit demselben Einzeiler auch die Umkehrung möglich ist: std::vector samples = {fMessage.samples().begin(), fMessage.samples().end()};

    – Wagner Volanin

    9. Juni 2021 um 22:26 Uhr


Benutzer-Avatar
Nazgul

Ich habe den kürzesten Weg gefunden, den Vektor in das wiederholte Feld zu kopieren:

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

Es ist wahrscheinlich auch schneller als Ihres, da es die anfängliche Iteration und das Setzen von Werten auf 0 vermeidet.

Die Antwort von @mgild wird implizit die aufrufen RepeatedField(Iter begin, Iter end) Konstruktor, um ein temporäres Element zu erstellen, das einer Verschiebung zugewiesen werden soll. Dasselbe gilt für die Antwort von @nazgul, die ausdrücklich erstellt ein temporäres RepeatedField und tauscht es aus.

Viel einfacher wäre es, die Erstellung eines neuen Objekts zu vermeiden:

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

Wenn samples Feld bereits nicht leer ist, können Sie anrufen Clear Methode vor.

Intern verwendet dies std::copy (so lange wie fData ist ein Vorwärts-Iterator), ist also genauso schnell wie jede Memcpy-Implementierung, die Sie sich ausdenken.

Benutzer-Avatar
David Toth

Als Alternative zu der ausgezeichneten Antwort von @mgild, Assign kann auch in dieser Situation verwendet werden, sodass die Daten vor dem Verschieben nicht in ein temporäres kopiert werden.

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

Gutschrift für die Antwort von Marek R

fMessage.mutable_samples()

gibt ein Array von Zeigern von Samples zurück: [*sample1, *sample2, sample3, …].

&fData[0]

ist die Adresse des ersten Elements von fData.

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

Ich glaube also nicht, dass der obige Code erfolgreich Daten von fData nach fMessage füllen kann. Es ist total falsch!

  • Nein tut es nicht. mutable_samples() weist auf a RepeatedField<float>und RepeatedField<float>::mutable_data kehrt zurück float*. Haben etwas Dokumentation.

    – Asteroiden mit Flügeln

    21. Oktober 2020 um 16:37 Uhr

  • Nein tut es nicht. mutable_samples() weist auf a RepeatedField<float>und RepeatedField<float>::mutable_data kehrt zurück float*. Haben etwas Dokumentation.

    – Asteroiden mit Flügeln

    21. Oktober 2020 um 16:37 Uhr

1015500cookie-checkKopieren Sie einen std::vector in ein wiederholtes Feld von protobuf mit memcpy

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy