template<typename Iterator> class move_iterator { Iterator current; public: typedef Iterator iterator_type; typedef typename std::iterator_traits<Iterator>::iterator_category iterator_category; typedef typename std::iterator_traits<Iterator>::value_type value_type; typedef typename std::iterator_traits<Iterator>::difference_type difference_type; typedef Iterator pointer; typedef value_type&& reference; move_iterator(){} explicit move_iterator(Iterator it):current(it){} template<typename Iter> move_iterator(const move_iterator<Iter>& it):current(it.current){} template<typename Iter> move_iterator& operator=(const move_iterator<Iter>&it) { current = it.current; } iterator_type base() const{ return current;} pointer operator->()const{return current;} reference operator*()const{return std::move(*current);} move_iterator&operator++(){++current; return *this;} move_iterator&operator--(){--current; return *this;} move_iterator&operator++(int){move_iterator temp = *this; ++current; return temp;} move_iterator&operator--(int){move_iterator temp = *this; --current; return temp;} move_iterator operator+(difference_type n) const {return move_iterator(current + n);} move_iterator operator-(difference_type n) const {return move_iterator(current - n);} move_iterator operator+=(difference_type n) {current += n; return *this;} move_iterator operator-=(difference_type n) {current -= n; return *this;} auto operator[](difference_type n) const -> decltype(std::move(current[n])) { return std::move(current[n]); } };
从实现上可以看出,基本是普通Iterator加了外包装。
其中特别值得注意的几个点:
typedef value_type&& reference; auto operator[](difference_type n) const -> decltype(std::move(current[n])) { return std::move(current[n]); } reference operator*()const{return std::move(*current);}
可以发现,这种迭代器呈现出差别就在解引用的时候强制转换成右值引用,这样就可以实现从一个容器中”移走“所有的元素
#include<vector> #include<algorithm> #include<stack> #include<iostream> #include<string> using namespace std; int main() { std::vector<std::string> foo(3); std::vector<std::string> bar{"one", "two", "three"}; typedef std::vector<std::string>::iterator Iter; std::copy(std::move_iterator<Iter>(bar.begin()), std::move_iterator<Iter>(bar.end()), foo.begin()); bar.clear(); std::cout << "foo:"; for(std::string& x : foo) cout << ' ' << x; std::cout << ' '; return 0; }
对于这个程序,可以跟踪一下,发现最后bar在copy之后,虽然仍旧含有三个元素,但都变成了"",可见已经被“掏空”了
后面那个clear只是使得bar的size减到0而已,可谓多此一举。
所有的差别,不过是因为我们输入参数用move_iterator裹了一层:std::move_iterator<Iter>(bar.begin())
还有就是move_iterator是模板类,不是模板函数,所以需要显式写出模板参数,在这里就显得有些啰嗦了。
还可以看一下另一个关于解引用的例子
#include<iterator> #include<string> #include<iostream> #include<vector> using namespace std; int main() { std::string str[] = {"one", "two", "three"}; std::vector<std::string> foo; std::move_iterator<std::string*> it(str); for(int i = 0; i < 3; i++) { foo.push_back(*it); ++it; } std::cout << "foo:"; for(std::string& x : foo) std::cout << " " << x; std::cout << " "; return 0; }
因为普通指针也可以被iterator_traits识别为迭代器,所以也可以用move_iterator进行包装