2017-08-29 60 views
7

Mam następujący C++ (11) Kod:Dlaczego std :: move na std :: unique_lock nie ma żadnego efektu?

#include <mutex> 

void unlock(std::unique_lock<std::mutex> && ulock) 
{ 
} 

int main(void) 
{ 
    std::mutex m; 
    std::unique_lock<std::mutex> ulock(m); 

    unlock(std::move(ulock)); 

    if (ulock.mutex() == &m || ulock.owns_lock()) 
    { 
     throw std::runtime_error(""); 
    } 

    return 0; 
} 

Nie mogę dowiedzieć się, dlaczego mutex jest nadal w posiadaniu po powrocie z unlock(). Oczekuję, że std::move() spowoduje wyjście blokady z zakresu (i odblokowanie przez destruktor) po powrocie z połączenia do unlock(). Przynajmniej wydaje się, że numer std::move() powinien spowodować, że ulock stanie się "niezwiązany" z muteksem m.

Czego mi brakuje?

+7

'std :: move' sam w sobie nie przenosi niczego. Po prostu rzuca lwartośc do referencji rvalue, pozwalając jej być argumentem konstruktorów ruchu i tym podobnych. Te z kolei mogą ukraść wewnętrzne elementy (jak sądzą) tymczasowe. Ale twój kod nie wywołuje żadnego z nich. 'unlock (std :: move (ulock));' jest skomplikowanym no-op. –

+0

Zdefiniuj 'unlock', aby uzyskać' std :: unique_lock' według wartości, a następnie przejdź do niego, aby zobaczyć efekty – WhiZTiM

+3

Założono, że std :: move() wywołał konstruktor ruchu dla unique_lock. Wygląda na to, że tak nie jest ... Raczej referencja rvalue w 'unlock()' jest "powiadomieniem" o sortowaniu, że * it * może użyć konstruktora ruchu, jeśli tak wybierze (jeśli ma to sens). –

Odpowiedz

12
void unlock(std::unique_lock<std::mutex> && ulock) 

Tutaj ulock jest odniesienia. Specjalny rodzaj odniesienia, ale wciąż odniesienie. Jest to tylko alias dla innego obiektu. Jego utworzenie nie wiąże się z tworzeniem nowego obiektu ani z jakimkolwiek rodzajem przeniesienia własności. Podobnie, koniec jego życia nie prowadzi do żadnego wywołania destruktora, to po prostu oznacza, że ​​straciłeś alias do odwoływania się do jakiegoś innego obiektu (nie ma to znaczenia, ponieważ i tak kończy się funkcja).

Jeśli chcesz przenieść własność, potrzebujesz obiekt, więc przechodzą przez wartość zamiast przez odniesienie:

void unlock(std::unique_lock<std::mutex> ulock) 

Teraz trzeba będzie move oryginalnego zamka, ponieważ std::unique_lock nie obsługuje kopiować konstrukcję, tylko przesuwać konstrukcję.