2015-01-28 2 views
6

Можно ли использовать std::unique с помощью итераторов, созданных с помощью функции std::make_move_iterator? Я пытался the following, и получил успех:уникальный алгоритм с итераторами перемещения

#include <iostream> 
#include <ostream> 
#include <vector> 
#include <algorithm> 
#include <limits> 
#include <iterator> 

#include <cstdlib> 

struct A 
{ 

    A() : i(std::numeric_limits<double>::quiet_NaN()) { std::cout << __PRETTY_FUNCTION__ << "\n"; } 
    A(double ii) : i(ii) { std::cout << __PRETTY_FUNCTION__ << "\n"; } 
    A(A const & a) : i(a.i) { std::cout << __PRETTY_FUNCTION__ << "\n"; } 
    A(A && a) : i(std::move(a.i)) { std::cout << __PRETTY_FUNCTION__ << "\n"; a.i = std::numeric_limits<double>::quiet_NaN(); } 
    A & operator = (A const & a) { std::cout << __PRETTY_FUNCTION__ << "\n"; i = a.i; return *this; } 
    A & operator = (A && a) { std::cout << __PRETTY_FUNCTION__ << "\n"; i = std::move(a.i); a.i = std::numeric_limits<double>::quiet_NaN(); return *this; } 
    bool operator < (A const & a) const { std::cout << __PRETTY_FUNCTION__ << "\n"; return (i < a.i); } 
#pragma clang diagnostic push 
#pragma clang diagnostic ignored "-Wfloat-equal" 
    bool operator == (A const & a) const { std::cout << __PRETTY_FUNCTION__ << "\n"; return (i == a.i); } 
#pragma clang diagnostic pop 

    friend 
    std::ostream & 
    operator << (std::ostream & o, A const & a) 
    { 
     return o << a.i; 
    } 

private : 

    double i; 

}; 

int 
main() 
{ 
    std::vector<A> v{1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 4.0, 4.0, 5.0, 6.0, 6.0, 7.0}; 
    std::cout << "v constructed\n\n\n\n"; 
    std::sort(v.begin(), v.end()); 
    auto const end = std::unique(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end())).base(); 
    std::copy(v.begin(), end, std::ostream_iterator<A>(std::cout, " ")); 
    std::cout << std::endl; 
    return EXIT_SUCCESS; 
} 

Но, возможно, это зависит от реализации успех?

А что относительно других алгоритмов от <numeric> и <algorithm>?

+0

'std :: unique' движется в любом случае, поэтому я не вижу, что вы получаете от него. –

+0

@ T.C. Что вы имеете в виду? 'std :: unique' copy-assigning [здесь] (http://en.cppreference.com/w/cpp/algorithm/unique) в разделе« Возможная реализация ». – Orient

+1

Это не очень хорошая реализация. Реальные библиотеки [move] (http://coliru.stacked-crooked.com/a/198b772ffc2f41ba). –

ответ

5

Программа гарантированно работает по стандарту.
std::unique требует итераторов переднего хода. Самый простой способ, чтобы показать, что перемещение итераторы удовлетворяет это требование, чтобы проверить iterator_category ЬурейиЕ из move_iterator:

typedef typename iterator_traits<Iterator>::iterator_category iterator_category; 

Как вы можете видеть, что итератор категория базового типа итератора непосредственно адаптированная. В самом деле, поведение хода итераторов почти эквивалентно лежащие в их основе те, [move.iterators]/1:

шаблон класса move_iterator является итератор адаптера с тем же поведением как основной итератор исключения того, что его косвенность оператор неявно преобразует значение, возвращаемое базовым оператором косвенности 10, к ссылке rvalue.

Там нет другого примечательного требования: Очевидно, vector<>::iterator является входным итератором (в соответствии с требованиями [move.iter.requirements]). Актуальной является только требование, предъявляемое самой unique является

тип *first должен удовлетворять требованиям MoveAssignable (таблица 22).

... который прямо встретил.

Обратите внимание, что использование итераторов перемещения не должно приносить никаких преимуществ перед нормальными. Внутренне дублирующиеся элементы назначаются по ходу (следовательно, требование MoveAssignable), поэтому возврат ссылки rvalue от operator* является излишним.

+0

Нет, внутренне 'std :: unique' должен непосредственно использовать назначение перемещения. Использование 'swap' потребует' MoveConstructible'. –

+0

@ T.C. Кажется правильным. Являются ли эти элементы фактически заменены или являются результатом после возврата нового конца в состоянии с переходом? – Columbo

+0

@ T.C. libstdC++, похоже, делает '* ++ __ dest = _GLIBCXX_MOVE (* __ first)', что указывает на то, что последнее верно. – Columbo

Смежные вопросы