std::vector-push_back mit std::move

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.

std::vector-push_back mit std::move

Beitragvon joggel » 12.09.2018, 12:11

Hallo,

nur mal eine eher kurze und recht simple Frage. Es geht um das verwenden von std::move.
Ich habe mal den relevanten Code auf ein minimum reduziert.

ich habe folgenden Code:
Code: Ansicht erweitern :: Alles auswählen

for(const auto& object : mMyVector)
{
        if(someExpresssion)
                mCollectorClass.addObject(object);
}
 

wobei
Code: Ansicht erweitern :: Alles auswählen

CollectorClass::addObject(const std::shared_ptr<Object>& anObject)
{
        myObjectVector.push_back(anObject);
}
 


nun Frage ich mich, ob ich nicht eher sowas schreiben kann:
Code: Ansicht erweitern :: Alles auswählen

CollectorClass::addObject(const std::shared_ptr<Object>&& anObject)
{
        myObjectVector.push_back(anObject);
}
 


wäre das nicht besser?
Ich habe das nämlich probiert, der vector mMyVector ist danach aber unverändert.
Mir scheint es auch so, als ob das push_back von std::vector keine überladung vom &&-Parameter hat.
Geht das also gar nicht was ich vorhabe?
Und wie müsste ich das denn realizieren?


Wie gesagt, sehr simple frage; modern C++ und so...^^
CEO of Dirty Codez Production®
Benutzeravatar
joggel
Establishment
 
Beiträge: 1364
Registriert: 06.11.2007, 19:06
Wohnort: Dresden

Re: std::vector-push_back mit std::move

Beitragvon dot » 12.09.2018, 12:59

joggel hat geschrieben:nun Frage ich mich, ob ich nicht eher sowas schreiben kann:
Code: Ansicht erweitern :: Alles auswählen

CollectorClass::addObject(const std::shared_ptr<Object>&& anObject)
{
        myObjectVector.push_back(anObject);
}
 

wäre das nicht besser?


Wenn, dann

Code: Ansicht erweitern :: Alles auswählen
CollectorClass::addObject(std::shared_ptr<Object>&& anObject)
{
    …
}


Eine rvalue Reference to non-const ist in der Regel sinnlos, weil man davon nicht moven kann (move Constructor erfordert normalerweise non-const source).

joggel hat geschrieben:Ich habe das nämlich probiert, der vector mMyVector ist danach aber unverändert.


Was genau meinst du mit "unverändert"? Wenn wirklich ein push_back() gemacht wird, dann muss der vector ein weiteres Element bekommen oder eine Exception fliegen. Ansonsten ist das ein extrem gravierender Bug in der Standardlibraryimplementierung deines Compilers. Dass push_back() erfolgreich returned aber einfach nichts tut, gibt es nicht…

joggel hat geschrieben:Mir scheint es auch so, als ob das push_back von std::vector keine überladung vom &&-Parameter hat.

Doch, anObject ist aber kein rvalue (eine named rvalue Reference bindet nur an rvalues, ist selbst aber ein lvalue), du müsstest explizit moven.

Abgesehen davon: emplace_back() is bae ;)

Und rein prinzipiell: Wieso shared_ptr? Hast du tatsächlich eine shared ownership Situation? shared_ptr sollte eigentlich nur in extrem seltenen Ausnahmefällen erforderlich sein. Für den Normalfall nimmt man unique_ptr
Benutzeravatar
dot
Michael Kenzel
Establishment
 
Beiträge: 1647
Registriert: 06.03.2004, 19:10

Re: std::vector-push_back mit std::move

Beitragvon joggel » 12.09.2018, 13:43

dot hat geschrieben:...
joggel hat geschrieben:Ich habe das nämlich probiert, der vector mMyVector ist danach aber unverändert.


Was genau meinst du mit "unverändert"? Wenn wirklich ein push_back() gemacht wird, dann muss der vector ein weiteres Element bekommen oder eine Exception fliegen. Ansonsten ist das ein extrem gravierender Bug in der Standardlibraryimplementierung deines Compilers. Dass push_back() erfolgreich returned aber einfach nichts tut, gibt es nicht…

mMyVector ist der Vector von dem ich die einträge moven möchte. Also über den ich iteriere und dann ggf. Einträge heraus nehme (eben mit move).
Aber ich werd es noch mal probieren mit non-const reference.

dot hat geschrieben:Und rein prinzipiell: Wieso shared_ptr? Hast du tatsächlich eine shared ownership Situation? shared_ptr sollte eigentlich nur in extrem seltenen Ausnahmefällen erforderlich sein. Für den Normalfall nimmt man unique_ptr

Ach... ich sitze hier an einem projekt, wo die eigentlich _fast_ alles in über ein std::shared_ptr gemacht haben. Ich würde das auch eher in 95% der fälle über einen raw-Zeiger machen.

Und emplace_back() schaue ich mir mal an.
Danke, ich werde das mal über diesen Weg probieren...

Edit:
Ja, ich würde auch eher fast alles mit unique_ptr machen und nur raw-pointer rausreichen, aber hier reichen die fast alles über shard_ptr raus, was ich auch fraglich finde...
CEO of Dirty Codez Production®
Benutzeravatar
joggel
Establishment
 
Beiträge: 1364
Registriert: 06.11.2007, 19:06
Wohnort: Dresden

Re: std::vector-push_back mit std::move

Beitragvon Helmut » 13.09.2018, 13:55

Probier's mal so:
Code: Ansicht erweitern :: Alles auswählen

for(auto& object : mMyVector)
{
        if(someExpresssion)
                mCollectorClass.addObject(std::move(object));
}
 
mit
Code: Ansicht erweitern :: Alles auswählen

CollectorClass::addObject(std::shared_ptr<Object>&& anObject)
{
        myObjectVector.push_back(std::move(anObject));
}
 


Dabei gehe ich davon aus, dass mMyVector ein vector<std::shared_ptr<Object>> ist.
Ich empfehle übrigens auch, std::shared_ptr möglichst zu vermeiden. Aber wenn du es nutzt, lohnt es sich nicht wirklich sich über Move-Semantik Gedanken zu machen. Einen std::shared_ptr zu kopieren ist nicht sonderlich teuer.
Helmut
Establishment
 
Beiträge: 229
Registriert: 11.07.2002, 15:49
Wohnort: Bonn

Re: std::vector-push_back mit std::move

Beitragvon dot » 13.09.2018, 14:24

Helmut hat geschrieben:Aber wenn du es nutzt, lohnt es sich nicht wirklich sich über Move-Semantik Gedanken zu machen. Einen std::shared_ptr zu kopieren ist nicht sonderlich teuer.

Hängt davon ab. Auch wenn es hier vermutlich kein großes Problem ist: Einen shared_ptr zu kopieren ist vermutlich doch um einiges teurer als einen unique_ptr zu kopieren. Nicht nur weil shared_ptr doppelt so groß ist, sondern insbesondere auch weil das Referencecountupdate ein atomic Fetch-and-add erfordert, welches vermutlich kaum ein Compiler wegoptimieren wird…

Beispiel clang:

Code: Ansicht erweitern :: Alles auswählen
void add(std::vector<std::shared_ptr<int>>& bla, std::shared_ptr<int>&& p)
{
    bla.emplace_back(p);
}

Code: Ansicht erweitern :: Alles auswählen
add()
  mov rax, qword ptr [rdi + 8]
  cmp rax, qword ptr [rdi + 16]
  jae .LBB0_4
  mov rcx, qword ptr [rsi]
  mov qword ptr [rax], rcx
  mov rcx, qword ptr [rsi + 8]
  mov qword ptr [rax + 8], rcx
  test rcx, rcx
  je .LBB0_3
  lock add qword ptr [rcx + 8], 1    ; ref count update (!?)
  mov rax, qword ptr [rdi + 8]
.LBB0_3:
  add rax, 16
  mov qword ptr [rdi + 8], rax
  ret
.LBB0_4:
  jmp void std::__1::vector<std::__1::shared_ptr<int>, std::__1::allocator<std::__1::shared_ptr<int> > >::__emplace_back_slow_path<std::__1::shared_ptr<int>&>(std::__1::shared_ptr<int>&) # TAILCALL


vs

Code: Ansicht erweitern :: Alles auswählen
void add(std::vector<std::shared_ptr<int>>& bla, std::shared_ptr<int>&& p)
{
    bla.emplace_back(std::move(p));
}

Code: Ansicht erweitern :: Alles auswählen
add()
  mov rax, qword ptr [rdi + 8]
  cmp rax, qword ptr [rdi + 16]
  jae .LBB0_2
  movups xmm0, xmmword ptr [rsi]
  movups xmmword ptr [rax], xmm0
  xorps xmm0, xmm0
  movups xmmword ptr [rsi], xmm0
  add qword ptr [rdi + 8], 16
  ret
.LBB0_2:
  jmp void std::__1::vector<std::__1::shared_ptr<int>, std::__1::allocator<std::__1::shared_ptr<int> > >::__emplace_back_slow_path<std::__1::shared_ptr<int> >(std::__1::shared_ptr<int>&&) # TAILCALL
Benutzeravatar
dot
Michael Kenzel
Establishment
 
Beiträge: 1647
Registriert: 06.03.2004, 19:10

Re: std::vector-push_back mit std::move

Beitragvon joggel » 14.09.2018, 08:30

Also wieder was gelernt (was ja auch total logisch ist): move bedarf non-const reference^^

Und ja, shared_ptr zu moven ist auch nicht gerade der sinnvollste Anwendungsfall. Aber mir geht es eher darum, dass ich versuche die "neuen" Features überall zu nutzen.

Danke für die Erklärung.

Edit:
Aber nur mal eine hypothetische Frage:
Was spricht eigentlich dagegen so oft wie möglich shared_ptr zu verwenden?
CEO of Dirty Codez Production®
Benutzeravatar
joggel
Establishment
 
Beiträge: 1364
Registriert: 06.11.2007, 19:06
Wohnort: Dresden

Re: std::vector-push_back mit std::move

Beitragvon Schrompf » 14.09.2018, 11:12

shared_ptr allokiert zwangsweise bei jedem Erzeugen, wenn Du nicht std::make_shared verwendest, sogar zweimal. Viele Sachen kann man stattdessen einfach einfach auf dem Stack anlegen. Und ich persönlich finde, dass shared_ptr nur ne Ausrede ist, um sich keine Gedanken über Lebenszeit und Besitz machen zu müssen.
Häuptling von Dreamworlds. Baut an was Neuem. Hilft nebenbei nur höchst selten an der Open Asset Import Library mit.
Benutzeravatar
Schrompf
Thomas Ziegenhagen
Moderator
 
Beiträge: 3767
Registriert: 26.02.2009, 00:44
Wohnort: Dresden
Benutzertext: Lernt nur selten dazu

Re: std::vector-push_back mit std::move

Beitragvon joggel » 17.09.2018, 08:03

Okay, das mit Allokation ist wirklich ein Argument; zumindest wenn man viele shared_ptrs hat.
Und das das auch irgendwie ein falsches SW-Designverständis ist sehe ich auch so...
CEO of Dirty Codez Production®
Benutzeravatar
joggel
Establishment
 
Beiträge: 1364
Registriert: 06.11.2007, 19:06
Wohnort: Dresden

Re: std::vector-push_back mit std::move

Beitragvon Schrompf » 17.09.2018, 09:03

Manchmal geht's nicht anders - wenn man mit externen Libs arbeitet, oder bei so asynchronen Basteleien mit Callbacks aus anderen Threads und wasweißichnoch. Aber hier isses echt simpel. Du nimmst einen std::vector aus echten Value Objekts, also schlicht std::vector<Object>. Und Du konstruierst neue Objekte direkt darin, also mit objects.emplace_back( ctor, params, ...);. Und wenn Du bereits ein Objekt hast, dann bewegst Du es in die Sammlung hinein mit objects.push_back( std::move(my_object) );
Häuptling von Dreamworlds. Baut an was Neuem. Hilft nebenbei nur höchst selten an der Open Asset Import Library mit.
Benutzeravatar
Schrompf
Thomas Ziegenhagen
Moderator
 
Beiträge: 3767
Registriert: 26.02.2009, 00:44
Wohnort: Dresden
Benutzertext: Lernt nur selten dazu


Zurück zu Programmiersprachen, Quelltext und Bibliotheken

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste