Using this answer, I invented my own method of emulating move-semantics in C++03 based on swap
.
First, I detect move-semantics (i.e. availability of C++03):
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || \
defined(_MSC_VER) && _MSC_VER >= 1600
#define HAS_MOVE_SEMANTICS 1
#elif defined(__clang)
#if __has_feature(cxx_rvalue_references)
#define HAS_MOVE_SEMANTICS 1
#else
#define HAS_MOVE_SEMANTICS 0
#endif
#else
#define HAS_MOVE_SEMANTICS 0
#endif
Then I conditionally define a macro called move
:
#if !HAS_MOVE_SEMANTICS
#include <algorithm>
namespace _cpp11_detail
{
template<bool B, class T = void> struct enable_if;
template<class T> struct enable_if<false, T> { };
template<class T> struct enable_if<true, T> { typedef T type; };
template<class T>
inline char (&is_lvalue(
T &, typename std::allocator<T>::value_type const volatile &))[2];
inline char (&is_lvalue(...))[1];
template<bool LValue, class T>
inline typename enable_if<!LValue, T>::type move(T v)
{ T r; using std::swap; swap(r, v); return r; }
template<bool LValue, class T>
inline typename enable_if<LValue, T>::type move(T &v)
{ T r; using std::swap; swap(r, v); return r; }
template<bool LValue, class T>
inline typename enable_if<LValue, T>::type const &move(T const &v)
{ return v; }
}
using _cpp11_detail::move;
namespace std { using _cpp11_detail::move; }
// Define this conditionally, if C++11 is not supported
#define move(...) move< \
(sizeof((_cpp11_detail::is_lvalue)((__VA_ARGS__), (__VA_ARGS__))) != 1) \
>(__VA_ARGS__)
#endif
Then I use it like this:
#include <vector>
std::vector<int> test(std::vector<int> v) { return std::move(v); }
int main()
{
std::vector<int> q(5, 5);
int x = 5;
int y = std::move(x);
std::vector<int> qq = test(std::move(test(std::move(q))));
}
My question is, how safe is this approach in practice? (assuming it compiles fine)
Are there any practical scenarios in which it could fail to work correctly in C++03 but not in C++11?
What about the opposite -- can it work correctly in C++11 but fail in C++03?
(Note: I'm looking for a practical answer, not a language-lawyer answer. I'm aware that defining new members in namespace std
is technically undefined, but in practice that won't cause issues on any compiler so I don't find that worth worrying about for the purposes of this question. I'm worried about cases such as accidental dangling references and the like.)
In C++11, the resources of the objects can be moved from one object to another rather than copying the whole data of the object to another. This can be done by using move semantics in C++11. Move semantics points the other object to the already existing object in the memory.
std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.
Move semantics allows you to avoid unnecessary copies when working with temporary objects that are about to evaporate, and whose resources can safely be taken from that temporary object and used by another.
std::move is actually just a request to move and if the type of the object has not a move constructor/assign-operator defined or generated the move operation will fall back to a copy.
move
does not move, but your move
does. This means that in C++11 a std::move
on an expression that does not assign it anywhere, or the consumer does not modify data. Yours does.
What is worse is that your move
blocks rvo/nrvo, just like C++11. In C++11 your return statement from test
would be a bad idea, as the return value would be implicitly move
ed. In C++03, as nrvo is blocked on arguments, it would be optimal. So the use of the two is different.
Your std::move
return value experiences reference lifetime extension, while the return value in C++11 does not. Code will have to be fully tested in both.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With