2016-12-08 2 views
-1

Lassen Sie uns den nächsten Code betrachten:Noch eine Optimierung mit Rvalue Referenz &&. Einfach umbenennen Felder

struct Channel; // somewhere declared 
using iter_t = std::set<Channel>::iterator; 

std::set<Channel> myset; 
std::pair<iter_t, bool> emplaced = myset.emplace(arg1,arg2); 

Dann Iterator Element emplaced.first enthält, wurde emplaced.second zeigt an, ob Element hinzugefügt oder bereits vorhanden sind. zuerst und Sekunde ist nicht klar, wie für mich. Ich möchte diese Felder umbenennen:

struct ChannelAddedResult 
{ 
    iter_t channelIter; 
    bool wasAdded; 
public: // --- Functions, constructors --- 
    ChannelAddedResult(std::pair<iter_t, bool> &&pa) { 
     this->channel = pa.first; 
     this->added = pa.second; 
    } 
}; 

Dieser Konstruktor kopiert Werte. Und hier ist kein Gewinn von Rvalue Referenz. Recht?
Aber wie kann ich std::pair<iter_t, bool> zu ChannelAddedResult konvertieren? Diese Typen sind gleichwertig. So C -Stil Gespräch könnte wie folgt aussehen:

union CarUni { 
    std::pair<iter_t, bool> pair; 
    ChannelAddedResult  car; 
} 
// Use 
CarUni u; 
u.pair = myset.emplace(arg1,arg2); 
auto ch = *u.car.channelIter; 
bool a = u.car.wasAdded; 

Dies ermöglicht ohne zusätzliche Kopien umbenennen zu erreichen. Kann sein C -casting (ChannelAddedResult)emplaced_pair wird die gleiche Arbeit, aber es ist in C++ veraltet. Diese 2 Umbauten sind aus der Sicht der Typsicherheit gefährlich.

Gibt es einen C++ 11-Weg für eine solche Umwandlung?

+1

Wo ist dieses Gespräch im C-Stil? Das ist alles C++. Und C-Style-Umwandlungen (die Sie * in Ihrem Beispiel * nicht verwendet haben) sind in C++ nicht veraltet. Alles in allem scheint Ihr Code gut und in keiner Weise "gefährlich vom Typ der Sicherheit". Worum geht es dir genau? –

+0

'std :: pair & emplaced == myset.emplace (arg1, arg2);' sollte 'std :: pair & emplaced = myset.emplace (arg1, arg2) sein;' – badola

+2

' std :: pair & emplaced == myset.emplace (arg1, arg2); 'vermeiden Sie es, Code zu posten, der aus Gründen, die nichts mit Ihrer Frage zu tun haben, nicht kompiliert wird. Ich denke, es gibt zwei Tippfehler, aber ... wenn es Tippfehler gibt, wie viele andere zufällige Funktionen Ihres Codes sind Tippfehler, die Sie nicht vorhatten? – Yakk

Antwort

1

Wenn Sie nicht zu kopieren, verschieben:

ChannelAddedResult(std::pair<iter_t, bool> &&pa) 
    : channel(std::move(pa.first)) 
    , added(std::move(pa.second)) 
{} 

Obwohl für Typen wie bool s und Iteratoren gibt es keinen wirklichen Unterschied.

1

Ich habe ein kleines Beispielprogramm geschrieben, um zu zeigen, wie ich es vielleicht versucht habe. Was ich von Ihrer Frage erhalten, ist, dass Sie die first und second von Paar mit Ihrem benutzerdefinierten Typ umbenennen möchten, d. H. channelIter und wasAdded.

Ich nahm Ihren Beispielcode und machte ein einfacheres Programm daraus.

#include <set> 
#include <iostream> 

struct Channel 
{ 
    int _a; // Declaring 2 simple args 
    int _b; 

    Channel(int a, int b) : _a(a), _b(b) {} 

    // Need to provide a < operator for custom datatype 
    bool operator<(Channel const & rhs) const { 
     return (this->_a < rhs._a) || (this->_b < rhs._b); 
    } 
}; 

using iter_t = std::set<Channel>::iterator; 

struct ChannelAddedResult 
{ 
    iter_t _channelIter; 
    bool _wasAdded; 

    ChannelAddedResult(std::pair<iter_t, bool> && pa) 
         : _channelIter(pa.first), _wasAdded(pa.second) {} 
}; 

int main() 
{ 
    std::set<Channel> myset; 
    auto u = ChannelAddedResult(myset.emplace(5, 6)); 
    auto ch = *u._channelIter; // Access pair.first 
    bool a = u._wasAdded;  // Access pair.second 

    std::cout << "ch._a => [" << ch._a << "] ch._b => [" << ch._b << "]\n"; 
    return 0; 
} 

Compile mit -std = C++ 11

$ g++ -std=c++11 set_sample.cpp -o set_sample 

Ausgabe

$ ./set_sample 
ch._a => [5] ch._b => [6] 

Punkt hier zu verstehen ist, dass ChannelAddedResult(std::pair<iter_t, bool> && pa) ist eine rvalue Referenz und soll einen R-Wert übergeben werden effizient genutzt werden. So sollte es wie ChannelAddedResult(myset.emplace(5, 6)) verwendet werden. Hier ist myset.emplace(5,6) ein rvalue. Also würde keine Kopie erstellt werden.

Im Gegenteil, wenn die Verwendung wie folgt war, wird dazwischen eine nutzlose Kopie erstellt. Das Übergeben eines Lvalue an einen Rvalue Reference vereitelt den ganzen Zweck.

auto val = myset.emplace(5,6); 
auto u = ChannelAddedResult(val); // val is an lvalue 

Der oben erwähnte Code wird jedoch nicht kompiliert. Damit es funktioniert würden Sie die Signatur als aktualisieren müssen -

ChannelAddedResult(std::pair<iter_t, bool> const & pa) 
        : _channelIter(pa.first), _wasAdded(pa.second) {} 

Jetzt wird es arbeiten beide mit rvalue und L-Wert. Da wir die Daten von std::pair bereits in andere Variablen kopieren, trägt die Verwendung der rvalue-Referenz nicht viel zur Leistung bei. Bessere Verwendung T const & pa anstatt T && pa, in dieser Situation.

+0

Rechts. Danke für das volle Programm. Ich habe versucht, meinen Posten so kurz wie möglich zu machen. Aber soweit ich verstehe '&& pa' gibt es kein Meter, da es genau so funktioniert wie 'const & pa' – kyb

+0

@kyb: Ihr Verständnis ist nicht korrekt. 'T && pa 'ist eine rvalue-Referenz und verwendet direkt den Wert von' myset.emplace (5, 6) '(da es in meinem Programm ein rvalue ist). Im Gegensatz dazu hätte die Verwendung von "T const & pa" anstelle von "T && pa" eine temporäre Kopie für dasselbe erstellt, die temporäre verwendet und später die temporäre Kopie zerstört. – badola

+0

Ich habe meine Antwort bearbeitet, um weitere Details zu Ihrem Zweifel hinzuzufügen. Gehe noch einmal durch. – badola

Verwandte Themen