Presentation is loading. Please wait.

Presentation is loading. Please wait.

Faster C++: Move Construction and Perfect Forwarding Pete Isensee Advanced Technology Group Microsoft.

Similar presentations


Presentation on theme: "Faster C++: Move Construction and Perfect Forwarding Pete Isensee Advanced Technology Group Microsoft."— Presentation transcript:

1 Faster C++: Move Construction and Perfect Forwarding Pete Isensee Advanced Technology Group Microsoft

2 Problem Statement Copying deep objects is expensive C++ is built on copy semantics – STL containers store by value – Compiler temporaries are copied by value Copying is often non-obvious in source code Games copy objects – a lot!

3 Example struct ParticleSystem { std::vector mPar; Texture mTex; }; Deeper ParticleSystem particleSys(...); particleSys = StartExplosion(); // Explosion begins particleSys += AddSmoke(); // More particles added struct Texture { unsigned long mSize; unsigned long* mpBits; }; Deep Shallow struct Particle { Vector3 mPos; Vector3 mVel; Color mCol; };

4 ParticleSystem particleSys(...); particleSys = StartExplosion(); // Explosion begins particleSys += AddSmoke(); // More particles added

5 ParticleSystem particleSys(...); particleSys = StartExplosion(); // Explosion begins particleSys += AddSmoke(); // More particles added particleSysStartExplosion() t v t … v t … v t … v t v t … v t v … … … t … v

6 Copying Temp Objects is Expensive Particles Copy (ticks) 16, , ,543 1,0008,579 10,00056, ,000635,962 1,000,0006,220,013 Perf of operator=(const ParticleSystem&)

7 Avoiding Temporaries is Difficult bool Connect( const std::string& server,... ); if( Connect( “microsoft.com” ) ) // temporary object created v.push_back( X(...) ); // another temporary a = b + c; // b + c is a temporary object a = b + c + d; // c+d is a temporary object // b+(c+d) is another temporary object x++; // returns a temporary object

8 What We Would Like… Is a world where… – We could avoid unnecessary copies – In cases where it was safe to do so – Completely under programmer control For example…

9 ParticleSystem particleSys(...); particleSys = StartExplosion(); // Explosion begins particleSys += AddSmoke(); // More particles added particleSysStartExplosion() t v t v t … v t v t v t … v t v … t … v …

10 Consider Assignment struct ParticleSystem { std::vector mPar; Texture mTex; }; ParticleSystem& operator=( const ParticleSystem& rhs ) { if( this != &rhs ) { mPar = rhs.mPar; // Vector assignment (copy) mTex = rhs.mTex; // Texture assignment (copy) } return *this; } Canonical copy assignment ParticleSystem& operator=( rhs ) { // move semantics here... return *this; } What we want

11 Solution: C++11 Standard to the Rescue Don’t copy when you don’t need to; move instead Critically important for deep objects Key new language feature: rvalue references Enables move semantics, including – Move construction – Move assignment – Perfect forwarding

12 Example ParticleSystem& operator=( const ParticleSystem& rhs ) { if( this != &rhs ) { mPar = rhs.mPar; // Particle vector copy mTex = rhs.mTex; // Texture copy } return *this; } Copy assignment ParticleSystem& operator=( ParticleSystem&& rhs ) { if( this != &rhs ) { mPar = std::move( rhs.mPar ); // Vector move mTex = std::move( rhs.mTex ); // Texture move } return *this; } Move assignment

13 Movable Objects: rvalues Move from = eviscerate thyself Every expression is either an lvalue or rvalue Always safe to move from an rvalue lvaluervalue In memoryyesno Can take its addressyesno Has a nameyesno Moveableno*yes

14 lvalue/rvalue examples X x; // x is an lvalue X(); // X() is an rvalue int a; // a is an lvalue int a = 1+2; // a is an lvalue; 1+2 is an rvalue foo( x ); // x is an lvalue foo( bar() ); // bar() is an rvalue ++x; // lvalue “abc” // lvalue *ptr // lvalue 4321 // rvalue x+42 // rvalue x++; // rvalue std::string( “abc” ) // rvalue

15 rvalue References T&: reference (pre C++11) T&: lvalue reference in C++11 T&&: rvalue reference; new in C++11 rvalue references indicate objects that can be safely moved from rvalue references bind to rvalue expressions lvalue references bind to lvalue expressions

16 Binding foo( ParticleSystem&& ); // A: rvalue foo( const ParticleSystem&& ); // B: const rvalue foo( ParticleSystem& ); // C: lvalue foo( const ParticleSystem& ); // D: const lvalue ParticleSystem particleSys; const ParticleSystem cparticleSys; foo( particleSys ); // lvalue foo( StartExplosion() ); // rvalue foo( cparticleSys ); // const lvalue

17 Binding and Overload Resolution Rules Expression Reference Type rvalueconst rvaluelvalueconst lvaluePriority T&&yeshighest const T&&yes T&yes const T&yes lowest

18 std::move std::move ~= static_cast (t) Tells compiler: treat this named variable as an rvalue Highly complex implementation due to reference collapsing, parameter deduction and other arcane language rules template inline typename std::remove_reference ::type&& move( T&& t ) noexcept { using ReturnType = typename std::remove_reference ::type&&; return static_cast ( t ); } ParticleSystem& operator=( ParticleSystem&& rhs ) { if( this != &rhs ) { mPar = std::move( rhs.mPar ); // Vector move assignment mTex = std::move( rhs.mTex ); // Texture move assignment } return *this; }

19 Move assign ParticleSystem& operator=( ParticleSystem&& rhs ) { if( this != &rhs ) { mPar = std::move( rhs.mPar ); // Vector move assignment mTex = std::move( rhs.mTex ); // Texture move assignment } return *this; } std::vector & operator=( std::vector && rhs ) { if( this != &rhs ) { DestroyRange( mpFirst, mpLast ); // call all dtors if( mpFirst != nullptr ) free( mpFirst ); mpFirst = rhs.mpFirst; // eviscerate mpLast = rhs.mpLast; mpEnd = rhs.mpEnd; // rhs now empty shell rhs.mpFirst = rhs.mpLast = rhs.mpEnd = nullptr; } return *this; } // Standard assignment operator Texture& Texture::operator=( const Texture& rhs ) { if( this != &rhs ) { if( mpBits != nullptr) free( mpBits ); mSize = rhs.mSize; mpBits = malloc( mSize ); memcpy( mpBits, rhs.mpBits, mSize ); } return *this; } Texture& Texture::operator=( Texture&& rhs ) { if( this != &rhs ) { if( mpBits != nullptr ) free( mpBits ); mpBits = rhs.mpBits; // eviscerate mSize = rhs.mSize; rhs.mpBits = nullptr; // clear rhs } return *this; }

20 Intermission Use rvalue reference semantics to enable moves Use non-const rvalue: rhs is reset std::move tells compiler “this is really an rvalue” Binding rules allow gradual conversion – Implement rvalue reference semantics as you go – Start in low-level libraries – Or start in high-level code, your choice

21 Performance Revisited Particles Copy (ticks) Move (ticks) 16, , , ,0008, ,00056, ,000635, ,000,0006,220, operator=(const ParticleSystem&) operator=(ParticleSystem&&)

22 Move Constructors ParticleSystem::ParticleSystem( ParticleSystem&& rhs ) : // invoke member move ctors mPar( std::move( rhs.mPar ) ), mTex( std::move( rhs.mTex ) ) { } vector ::vector( vector && rhs ) : mpFirst( rhs.mpFirst ), // eviscerate mpLast ( rhs.mpLast ), mpEnd ( rhs.mpEnd ) { // rhs now an empty shell rhs.mpFirst = rhs.mpLast = rhs.mpEnd = nullptr; } Texture::Texture( Texture&& rhs ) : mpBits( rhs.mpBits ), // eviscerate mSize( rhs.mSize ) { // rhs now an empty shell rhs.mpBits = nullptr; }

23 Perfect Forwarding Problem Suppose we have some setter functions void ParticleSystem::SetTexture( const Texture& texture ) { mTex = texture; // We’d like to move if tx is a temporary } void ParticleSystem::SetTexture( Texture&& texture ) { mTex = std::move( texture ); // Move } void ParticleSystem::Set( const A& a, const B& b ) { // Uh-oh, we need three new overloads... }

24 Func Templates Plus rvalues to the Rescue Powerful new rule in C++11. Given: Template rvalue ref param binds to anything template void f( T&& t ); // template function Expression Reference Type rvalueconst rvaluelvalueconst lvaluePriority template T&&yes highest T&&yes const T&&yes T&yes const T&yes lowest

25 Binding rvalue Reference Template Params Examples template void f( T&& t ); // template function int a; const int ca = 42; f( a ); // instantiates f( int& ); f( ca ); // instantiates f( const int& ); f( StartExplosion() ); // instantiates f( ParticleSystem&& );

26 Perfect Forwarding template void ParticleSystem::SetTexture( T&& texture ) { mTex = std::forward ( texture ); // invokes right overload } template inline T&& // typical std::forward implementation forward( typename identity ::type& t ) noexcept { return static_cast ( t ); } std::forward equivalent to – static_cast (t) when t is an rvalue – static_cast (t) when t is an lvalue

27 Perfect Constructors ParticleSystem::ParticleSystem( const std::vector & par, const Texture& texture ) : mPar( par ), mTex( texture ) { } Typical multi-arg ctor; doesn’t handle rvalues template ParticleSystem::ParticleSystem( V&& par, T&& texture ) : mPar( std::forward ( par ) ), mTex( std::forward ( texture ) ) { } Perfect constructor; handles everything you throw at it!

28 Implicit Special Member Functions Rule of Three: if you define any of the first three, define all Rule of Two Moves: If you define either move, define both FunctionImplicitly generated when Default ctorno other ctor explicitly declared Copy ctorno move ctor or move assign explicitly declared Copy assignno move ctor or move assign explicitly declared Move ctorno copy ctor, move assign or dtor explicitly declared Move assignno copy ctor, copy assign or dtor explicitly declared Dtorno dtor explicitly declared

29 Be Explicit About Implicit Special Functions struct ParticleSystem { std::vector mPar; // Copyable/movable object Texture mTex; // Copyable/movable object // Ctors ParticleSystem() = delete; ParticleSystem( const ParticleSystem& ) = default; ParticleSystem( ParticleSystem&& ) = default; // Assign ParticleSystem& operator=( const ParticleSystem& ) = default; ParticleSystem& operator=( ParticleSystem&& ) = default; // Destruction ~ParticleSystem() = default; };

30 C++11 STL containers move enabled – Including std::string STL algorithms move enabled – Including sort, partition, swap You get immediate speed advantages simply by recompiling template swap( T& a, T& b ) { T tmp( std::move( a ) ); a = std::move( b ); b = std::move( tmp ); }

31 Recommended Idioms: Moveable Types struct Deep { Deep( const Deep& ); // Copy ctor Deep( Deep&& ); // Move ctor template Deep( A&&, B&& ); // Perfect forwarding ctor Deep& operator=( const Deep& ); // Copy assignment Deep& operator=( Deep&& ); // Move assignment ~Deep(); template // Deep setters void SetA( A&& ); };

32 Recommended Idioms: Raw Pointers T( T&& rhs ) : ptr( rhs.ptr ) // eviscerate { rhs.ptr = nullptr; // rhs: safe state } T& operator=( T&& rhs ) { if( this != &rhs ) { if( ptr != nullptr ) free( ptr ); ptr = rhs.ptr; // eviscerate rhs.ptr = nullptr; // rhs: safe state } return *this; } Move ctor Move assignment

33 Recommended Idioms: Higher Level Objs T( T&& rhs ) : base( std::move( rhs ) ), // base m ( std::move( rhs.m ) ) // members { } T& operator=( T&& rhs ) { if( this != &rhs ) { m = std::move( rhs.m ); // eviscerate } return *this; } Move ctor Move assignment

34 Recommended Idioms: Perfect Forwarding template T( A&& a, B&& b ) : // binds to any 2 params ma( std::forward ( a ) ), mb( std::forward ( b ) ) { } template void SetA( A&& a ) // binds to anything { ma = std::forward ( a ); } Ctor Setter

35 Compilers and Move Support FeatureMicrosoftGCCIntelClang rvalue referencesVS STL move semanticsVS nullptrVS variadic templates defaulted/deleted funcs noexcept Exhaustive list:

36 High Level Takeaways By overloading on rvalue references, you can branch at compile time on the condition that x is moveable (a temporary object) or not You can implement the overloading gradually Benefits accrue to deep objects Performance improvements can be significant

37 Further Research: Topics I Didn’t Cover xvalues, glvalues, prvalues Emplacement (e.g. “placement insertion”) – Create element within container, w/ no moves/copies – Uses perfect forwarding and variadic functions Other scenarios where moving lvalues is OK Moves and exceptions Perfect forwarding not always so perfect – e.g. integral and pointer types; bitfields, too noexcept and implicit move

38 Best Practices Update to compilers that support rvalue references Return by value is now reasonable – both readable and fast Add move ctor/assignment/setters to deep objects Move idiom: this = rhs pointers, rhs pointers = null Use non-const rvalue references When moving, satisfy moved-from obj invariants Avoid return by const T – prevents move semantics Be explicit about implicit special functions Step thru new move code to ensure correctness

39 Thanks! Contact me: Slides: Scott Meyers: Stephan Lavavej: Dave Abrahams: Thomas Becker: Marc Gregoire: Let me know what kind of results you see when you move enable your code

40 Additional Reference Material

41 C++ Standard References N1610 (v0.1) std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.htmlhttp://www.open- std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.html N2118 (v1.0) std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.htmlhttp://www.open- std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html N2844 (v2.0) 2009 (VC10 impl) std.org/jtc1/sc22/wg21/docs/papers/2009/n2844.htmlhttp://www.open- std.org/jtc1/sc22/wg21/docs/papers/2009/n2844.html N3310 (sections 840, 847, 858) (v2.1) 2011 (VC11 impl) std.org/jtc1/sc22/wg21/docs/cwg_defects.html std.org/jtc1/sc22/wg21/docs/cwg_defects.html N3053 (v3.0) std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.htmlhttp://www.open- std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.html

42 rvalue References Scott Meyers’ Move Semantics and rvalue References: and references references Scott Meyers’ Adventures in Perfect Forwarding (C++ and Beyond 2011) Thomas Becker’s rvalue References Explained: STL’s blog: features-in-vc10-part-2.aspx?PageIndex=3http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x- features-in-vc10-part-2.aspx?PageIndex=3 Marc Gregoire’s Blog visual-c-2010/http://www.nuonsoft.com/blog/2009/06/07/the-move-constructor-in- visual-c-2010/ C++11 Features in Visual Studio C Mikael Kilpelainen’s Lvalues and Rvalues Moving from lvalues Binary operators Emplacement


Download ppt "Faster C++: Move Construction and Perfect Forwarding Pete Isensee Advanced Technology Group Microsoft."

Similar presentations


Ads by Google