В своей презентации “С++ 11 usage experience: Move semantic”, Дмитрий Гурин, bp GlobalLogic, рассказывает о части нововведений нового стандарта C++, особенностях работы с объектами rvalue и lvalue, а также особенностями использования функций std::move и std::forward. В конце доклада — полезные советы по оптимизации кода с применением возможностей нового стандарта С++.
Напомним, Embedded Kyiv TechTalk состоялся 14 декабря 2013 года.
8. lvalue
•
•
identifies a non-temporary object.
prvalue
“pure rvalue” - identifies a temporary object or is a
value not associated with any object.
xvalue
•
either temporary object or non-temporary object at
the end of its scope.
glvalue
•
•
either lvalue or xvalue.
rvalue
either prvalue or xvalue.
9. class Buffer {
char* _data;
size_t _size;
// ...
// copy the content from lvalue
Buffer(Buffer const& lvalue)
: _data(nullptr), _size(0)
{
// perform deep copy ...
}
// take the internals from rvalue
Buffer(Buffer&& rvalue)
: _data(nullptr), _size(0)
{
swap(_size, rvalue._size);
swap(_data, rvalue._data);
// it is vital to keep rvalue
// in a consistent state
}
// ...
Buffer getData() { /*...*/ }
// ...
Buffer someData;
// ... initialize someData
Buffer someDataCopy(someData);
// make a copy
Buffer anotherData(getData());
// move temporary
11. Does not really move anything;
Does cast a reference to object to
xvalue:
template<typename _T>
typename remove_reference<_T>::type&&
move(_T&& t) {
return static_cast<typename remove_reference<_T>::type&&>(t);
}
Does not produce code for run-time.
12.
Move is an optimization for copy.
Copy of rvalue objects may become
move.
Explicit move for objects without move
support becomes copy.
Explicit move objects of built-in types
always becomes copy.
13. Compiler does generate move
constructor/assignment operator when:
•
•
•
there is no user-defined copy or move operations (including
default);
there is no user-defined destructor (including default);
all non-static members and base classes are movable.
Implicit move constructor/assignment operator
does perform member-wise moving.
Force-generated move operators does perform
member-wise moving:
•
dangerous when dealing with raw resources (memory, handles,
etc.).
15. class Configuration {
// have copy & move operations implemented
// ...
};
class ConfigurationManger {
// ...
Configuration _current;
// ...
template <class _ConfigurationRef>
explicit ConfigurationManager(_ConfigurationRef&& defaultConfig)
: _current(forward<_ConfigurationRef>(defaultConfig))
// OK, deal with either rvalue or lvalue
{ }
// ...
};
16. Normally
C++ does not allow reference to
reference types.
Template types deduction often does
produce such types.
There are rules for deduct a final type then:
•
•
•
•
T& &
T&
T& && T&
T&& & T&
T&& && T&&
17. Just a cast as well;
Applicable only for function templates;
Preserves arguments
lvaluesness/rvaluesness/constness/etc.
template<typename _T>
_T&&
forward(typename remove_reference<_T>::type& t) {
return static_cast<_T&&>(t);
}
template<typename _T>
_T&&
forward(typename remove_reference<_T>::type&& t) {
return static_cast<_T&&>(t);
}
23. The hardest work for move semantic
support usually performed by the compiler
and the Standard Library.
There is still a lot of space for apply move
semantic explicitly for performance critical
parts of the application:
• It is up to developer to ensure the code correctness
when the move semantic used explicitly.
• The best way to add move semantic support to own
class is using pImpl idiom.