2014-10-17 17 views
6

Starałem się zrobić coś takiego:Czy std :: move i std :: copy identical?

std::copy(std::make_move_iterator(s1.begin()), std::make_move_iterator(s1.end()), 
      std::make_move_iterator(s2.begin())); 

I got ten błąd:

error: using xvalue (rvalue reference) as lvalue 
     *__result = std::move(*__first); 

co wydawało się dziwne dla mnie. To samo dzieje się, jeśli używasz std::move. Wygląda na to, że GCC używa wewnętrznie funkcji o nazwie std::__copy_move_a, która porusza się zamiast kopiować. Czy ma znaczenie, czy używasz std::copy lub std::move?


#include <string> 
#include <iostream> 
#include <algorithm> 
#include <iterator> 
#include <cstring> 

struct Test 
{ 
    typedef std::string::value_type value_type; 
    std::string data; 

    Test() 
    { 
    } 

    Test(const char* data) 
     : data(data) 
    { 
    } 

    ~Test() 
    { 
    } 

    Test(const Test& other) 
     : data(other.data) 
    { 
     std::cout << "Copy constructor.\n"; 
    } 

    Test& operator=(const Test& other) 
    { 
     data = other.data; 
     std::cout << "Copy assignment operator.\n"; 
     return *this; 
    } 

    Test(Test&& other) 
     : data(std::move(other.data)) 
    { 
     std::cout << "Move constructor.\n"; 
    } 

    decltype(data.begin()) begin() 
    { 
     return data.begin(); 
    } 

    decltype(data.end()) end() 
    { 
     return data.end(); 
    } 

    void push_back(std::string::value_type ch) 
    { 
     data.push_back(ch); 
    } 
}; 

int main() 
{ 
    Test s1("test"); 
    Test s2("four"); 
    std::copy(std::make_move_iterator(s1.begin()), std::make_move_iterator(s1.end()), 
       std::make_move_iterator(s2.begin())); 
    std::cout << s2.data; 
} 
+0

dlaczego przenosisz iterator z 's2.begin()'? –

Odpowiedz

5

std::move przenosi elementy, jeśli to tylko możliwe, kopie inaczej. std::copy będzie zawsze kopiować.

libstdC++ 's copy_move_a przyjmuje również parametr szablonu _IsMove. To i typy iteratorów przekazują szablon klasy __copy_move, który jest częściowo wyspecjalizowany dla różnych kategorii iteratorów, itp., Ale co najważniejsze: niezależnie od tego, czy jest to move czy nie. Jednym z kierunków jest

#if __cplusplus >= 201103L 
    template<typename _Category> 
    struct __copy_move<true, false, _Category> 
    // first specialized template argument is whether to move 
    { 
     template<typename _II, typename _OI> 
     static _OI 
     __copy_m(_II __first, _II __last, _OI __result) 
     { 
     for (; __first != __last; ++__result, ++__first) 
     *__result = std::move(*__first); // That may be your line 
     return __result; 
    } 
    }; 
#endif 

Twój kod nie skompilować do zupełnie innego powodu: Drugi zakres jest podany przez move_iterator s. Jeśli je usuniesz, zwracają one odniesienie do obiektu - i nie możesz przypisać czegoś do wartości x typu skalarnego.

int i; 
std::move(i) = 7; // "expression not assignable" -- basically what your code does 

The std::move jest domyślnie włączone *__result i jest z tej samej kategorii wartości, czyli o xvalue.

Dla przykładu,

std::copy(std::make_move_iterator(s1.begin()), std::make_move_iterator(s1.end()), 
      s2.begin()); 

powinny działać prawidłowo.

16

std::move(a, b, c); jest semantycznie identyczne

std::copy(std::make_move_iterator(a), 
      std::make_move_iterator(b), 
      c); 

swoje wysiłki, aby wykorzystać je zarówno powiodła się, ponieważ trzeci argument - iterator wyjście - powinien nie być iterator pojedynek. Przechowujesz w trzecim iteratorze, nie ruszasz się z niego. Zarówno

std::copy(std::make_move_iterator(s1.begin()), 
      std::make_move_iterator(s1.end()), 
      s2.begin()); 

i

std::move(s1.begin(), s1.end(), s2.begin()); 

powinien robić, co chcesz.

Powiązane problemy