2013-02-25 15 views
7

to:otrzymuję błąd, albo przynajmniej ostrzeżenie, gdy przy użyciu zmiennej, która została std :: move'ed gdzie indziej

void foo(int &&r) { 
    std::cout << r << std::endl; 
} 

int main() { 
    int i = 2; 
    foo(std::move(i)); 
    i = 3; //no warning. any way to get some warnings here? 
    return 0; 
} 

Czy nie ma sposobu, aby poinformować kompilator dać mi błąd (lub ostrzeżenie), jeśli przypadkowo użyję zmiennej po jej przeniesieniu? Myślę, że byłoby to bardzo wygodne. Wiele razy znajduję ruchome zmienne gdzie indziej, ale potem muszę być BARDZO DŁUŻĄ, że nie używam ich później. Teraz to nie sprawiło jeszcze żadnych problemów, ale kto wie w dół ... lepiej być bezpiecznym!

Być może istnieją jakieś preprocesorowe oszustwa (lub dość szeroko dostępne rozszerzenia kompilatorów), które istnieją, aby zrobić te rzeczy?


Bardziej realistyczny przykład:

struct HugeStorage { 
    std::vector<double> m_vec; 
    HugeStorage(std::vector<double> vec) : m_vec(std::move(vec)) { } 
}; 

struct SmallStorage { 
    std::vector<double> m_vec; 
    SmallStorage(std::vector<double> vec) : m_vec(std::move(vec)) { } 
}; 

std::vector<double> vec_from_data_source() { 
    return std::vector<double>(); //only example!! 
} 

int main() { 
    std::vector<double> vec = vec_from_data_source(); 
    if (vec.size() > 10000) 
    { 
    HugeStorage storage(std::move(vec)); 
    //do some things, but I gotta be careful I don't do anything to vec 
    } 
    else 
    { 
    SmallStorage storage(std::move(vec)); 
    //do some things, but I gotta be careful I don't do anything to vec 
    } 
    return 0; 
} 
+2

Zmienna nie została przeniesiona, tylko jej wartość. Nie ma absolutnie nic złego w przypisywaniu jej nowej wartości. –

+0

Jakie "kłopoty" przewidujesz i jaki jest * rzeczywisty * problem z kodem, który wyświetlasz? –

+0

@NikBougalis Aktualizacja bardziej realistyczny przykład – user2015453

Odpowiedz

10

Czy nie ma sposobu, aby poinformować kompilator dać mi błąd (lub ostrzeżenie), jeśli przypadkowo użyć zmiennej po tym jak przeniósł go?

Odpowiedź jest „nie, nie ma sposobu” (do mojej najlepszej wiedzy przynajmniej nie aktualnie dostępny kompilator oferuje taką opcję, a za dobry powód - patrz niżej).

Nawet jeśli to było w ogóle możliwe, dlatego można oczekiwać ostrzeżenie, lub nawet gorzej błąd, należy podać w tym przypadku? Po pierwsze, przejście od liczby całkowitej nie różni się niczym od jej kopiowania.

Po drugie, dla typów najwięcej przypisanie obiektu przeniesionego z tego typu jest operacją całkowicie legalną; to jest zawsze prawdziwe podstawowych typów takich jak int, i to jest na pewno prawdziwe std::vector, chociaż to nie może być prawdą innych typów.

Ogólnie czy przypisywania przemieszczające się z przedmiotem jest legalny, zależy od danego stanowiska-warunków pracy ruch dla tego typu i warunków koniecznych operatora przypisania (operatorowi przypisanie typów Biblioteki standardowa nie ma żadnych warunków wstępnych po lewej stronie argumentu). Jest to coś, czego kompilator nie może sprawdzić w ogólnym przypadku.

Dlatego też, jeśli było:

  1. Przejście od obiektu, dla którego zadanie przenieść lub przenieść konstruktora miejscach przeniósł-z obiektu w stanie nieokreślonym (to jest w przypadku std::vector) oraz następnie;
  2. Wywołanie żadnej funkcji w warunków na stan tego przedmiotu (i to nie w przypadku przypisania do std::vector);

To z pewnością byłoby źle.Z drugiej strony, kompilator nie ma sposobu, aby przeprowadzić semantycznej analizy swojego programu i dowiedzieć się, czy jest to przypadek:

A x, y; 
... 
if (complicatedCondition()) 
{ 
    y = move(x); 
} 

foo(x); // Did I move from x? And if so, is it safe to call foo()? 

Ponadto, nie należy zapominać, że filozofia C++ jest aby dać ci moc i (najczęściej) wskazówki projektowe, ale "pozwala ci strzelać stopami", jeśli naprawdę chcesz to zrobić.

Nie niebezpieczne, nawet bezsensowne rzeczy, które można zrobić w C++ (będzie kompilator daje ostrzeżenie lub błąd, jeśli spróbujesz delete ten sam wskaźnik dwukrotnie?), Ale język sam wygrał” t przeszkadza ci to robić, zakładając, że naprawdę, naprawdę wiesz, co robisz.

+0

Dla typów bibliotek nie ma gwarancji, że obiekt jest * możliwy do przypisania *, tylko że jest * możliwy do zniszczenia *. Biorąc to pod uwagę, wiele wdrożeń bibliotecznych zapewni dodatkową gwarancję tego, czego wymaga standard. –

+6

@ DavidRodríguez-dribeas: 17.6.5.15/p1 gwarantuje, że wszystkie przeniesione z typów std :: lib będą w ważnym, ale nieokreślonym stanie. Oznacza to, że jeśli typy mają warunek wstępny w lhs instrukcji przypisania, można ją przypisać, nawet po przeniesieniu z. Zwróć uwagę, że to ogólne stwierdzenie dotyczy typów w standardowej wersji, a nie ogólnie typów. I nie jestem świadomy jakiegokolwiek std :: type, który ma warunek wstępny do przypisania. –

+1

@HowardHinnant: Dziękuję za wyjaśnienie. –

0

Chyba próbują wykorzystać posunięcie jako zamiennik zmiennego zakresu.

int main() 
{ 
    { 
    int i = 2; 
    foo(std::move(i)); 
    } 
    i = 3; // error! 
    return 0; 
} 
+0

Dobrze, że pracuje w najprostszych przypadkach, ale jest to coś ... – user2015453

+0

myślę użyć semantykę move niewłaściwy sposób, jakaś wymiana zakresie, moja odpowiedź jest pokazujące, że uczynić bardziej prawdziwy przykład wtedy możemy patrzeć. – Slava

5
//do some things, but I gotta be careful I don't do anything to vec 

Wyjaśnienie: Trzeba uważać, aby nie zrobić nic, aby vec wymagającej warunek. Ci może zrobić coś z vec, dokłada nie wymaga żadnych warunków wstępnych. Na przykład można przypisać nową wartość vec. Możesz zadzwonić pod numer vec.clear(). Możesz zadzwonić pod numer vec.size(). Ale nie dzwoń pod numer vec.pop_back(), ponieważ funkcja tego elementu ma warunek wstępny.

+2

W przypadku, gdy nie jest to oczywiste dla wszystkich, chciałbym wyjaśnić, że nie można zrobić niczego, co wymaga warunku wstępnego bez uprzedniego sprawdzenia tego warunku. Dobrze jest wywołać 'if (! Vec.empty()) vec.pop_back();' ponieważ po wywołaniu 'vec.empty()' wiesz, że warunek jest spełniony –

+1

Tak, lepiej powiedzieć, dziękuję Jonathan. –

Powiązane problemy