Переместить конструктор для std :: mutex - PullRequest
35 голосов
/ 26 сентября 2011

Многие классы в стандартной библиотеке c ++ теперь имеют конструкторы перемещения, например -

thread::thread(thread&& t)

Но похоже, что std :: mutex - нет. Я понимаю, что они не могут быть скопированы, но, кажется, имеет смысл возвращать один из функции "make_mutex", например. (Не говоря, что это полезно, просто это имеет смысл)

Есть ли причина, по которой std :: mutex не имеет конструктора перемещения?

Ответы [ 2 ]

39 голосов
/ 26 сентября 2011

Ну ... главным образом потому, что я не думаю, что они должны двигаться . В прямом смысле.

В некоторых ОС мьютекс может быть смоделирован как дескриптор (чтобы вы могли его скопировать), но IIRC мьютекс pthreads манипулирует на месте. Если вы собираетесь переместить это, любая безопасность потоков вылетит прямо из окна (как другие потоки узнают, что мьютекс только что изменил свой адрес памяти ...)?

16 голосов
/ 27 сентября 2011

Помните, что C ++ принимает философию «не плати за то, что не используешь». Давайте рассмотрим, например, воображаемую платформу, которая использует непрозрачный тип для представления мьютекса; давайте назовем этот тип mutex_t. Если интерфейс для работы с этим мьютексом использует mutex_t* в качестве аргументов, например, например, void mutex_init(mutex_t* mutex); для «создания» мьютекса, вполне возможно, что адрес мьютекса используется для уникальной идентификации мьютекса. Если это так, то это означает, что mutex_t не копируется:

mutex_t kaboom()
{
    mutex_t mutex;
    mutex_init(&mutex);
    return mutex; // disaster
}

Здесь не гарантируется, что при mutex_t mutex = kaboom(); значение &mutex совпадает со значением &mutex в функциональном блоке.

Когда придет день, когда разработчик захочет написать std::mutex для этой платформы, если требования этого типа являются подвижными, то это означает, что внутренний mutex_t должен быть помещен в динамически выделяемую память со всеми связанные штрафы.

С другой стороны, хотя прямо сейчас std::mutex является не подвижным, очень легко «вернуть» функцию из функции: вместо нее вернуть std::unique_ptr<std::mutex>. Это по-прежнему оплачивает затраты на динамическое распределение , но только в одном месте . Весь другой код, который не нужно перемещать std::mutex, не должен оплачивать это.

Другими словами, поскольку перемещение мьютекса не является основной операцией того, что такое мьютекс, отсутствие необходимости в перемещении std::mutex не отменяет никакой функциональности (благодаря неподвижному T => подвижное преобразование std::unique_ptr<T>) и потребует минимальных накладных расходов по сравнению с непосредственным использованием собственного типа.


std::thread аналогичным образом можно было бы указать, чтобы оно не было подвижным, что могло бы привести к тому, что типичное время жизни было бы таким: выполнение (связанное с потоком выполнения), после вызова оцененного конструктора; и отсоединен / присоединен (связан с отсутствием потока выполнения) после вызова join или detach. Насколько я понимаю, std::vector<std::thread> все еще можно было бы использовать, так как тип был бы EmplaceConstructible.

редактировать: неверно! Тип все еще должен быть подвижным (при перераспределении в конце концов). Так что для меня это достаточно логично: обычно помещать std::thread в контейнеры, такие как std::vector и std::deque, поэтому функциональность этого типа приветствуется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...