使用this answer,我发明了自己的基于swap
在C ++ 03中模拟移动语义的方法。
首先,我检测移动语义(即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
然后我有条件地定义了一个名为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
然后我像这样使用它:
#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))));
}
我的问题是, 安全在实践中是如何实现的?(假设编译正常)
是否有任何实际情况可能无法在C ++ 03中正常工作但在C ++ 11中无法正常工作?
相反的情况 - 它可以在C ++ 11中正常工作但在C ++ 03中失败吗?
(注意:我正在寻找一个实用的答案,而不是语言律师的答案。我知道在namespace std
中定义新成员在技术上是未定义的,但在实践中这不会对任何编译器造成问题,所以我发现这个问题的目的并不值得担心。我担心偶然悬挂引用等情况。)
答案 0 :(得分:3)
move
不会移动,但您的move
会移动。这意味着在C ++ 11中,表达式上的std::move
不会将其分配到任何地方,或者消费者不会修改数据。你的确如此。
更糟糕的是,你的move
阻止了rvo / nrvo,就像C ++ 11一样。在C ++ 11中,来自test
的返回语句是个坏主意,因为返回值将隐式move
。在C ++ 03中,由于nrvo在参数上被阻塞,因此它是最佳的。所以两者的使用是不同的。
您的std::move
返回值会经历引用生命周期扩展,而C ++ 11中的返回值则不会。代码必须在两者中进行全面测试。
答案 1 :(得分:0)
执行摘要似乎是,“只要你按常规方式使用它就是安全的。”