Насколько безопасен этот метод эмуляции семантики перемещения в C++03?
используя ответ, я изобрел свой собственный метод эмуляции семантики перемещения в C++03 на основе swap
.
во-первых, я обнаруживаю семантику перемещения (т. е. доступность 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
технически не определено, но на практике это не вызовет проблемы с любым компилятором, поэтому я не считаю, что стоит беспокоиться об этом для целей этого вопроса. Я беспокоюсь о таких случаях, как случайные болтающиеся ссылки и тому подобное.)
2 ответов
move
не двигается, но ваш move
делает. Это означает, что в C++11 есть std::move
на выражение, которое не назначает его нигде, или потребитель не изменяет данные. Ваш.
что хуже, что ваш move
блокирует rvo / nrvo, как и C++11. В C++11 ваш оператор return из test
было бы плохой идеей, так как возвращаемое значение было бы неявно move
ed. В C++03, поскольку nrvo блокируется по аргументам, это было бы оптимальным. Поэтому использование двух отличающийся.
код std::move
return value experiences reference lifetime extension, в то время как возвращаемое значение в C++11 этого не делает. Код должен быть полностью протестирован в обоих.