Ссылка std::thread и rvalue
Я хотел иметь какой-то класс делегатов. Укороченная версия моего подхода приведена ниже, и его основная функциональность заключается в том, чтобы запускать новый поток, делая что-то (в этом примере он печатает текст каждую секунду):
void Flusher::start(){
m_continue.store(true);
m_thread = std::thread([](std::atomic<bool>& shouldContinue){
while(shouldContinue.load()){
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "sec passed" << std::endl;
}}, std::ref<std::atomic<bool>>(m_continue)
);
}
Меня беспокоит то, что конструктор std::thread имеет следующую подпись:
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );
Таким образом, в качестве первого и второго аргумента используется ссылка на значение. Если это так, то я не должен использовать shouldContinue
после передачи его std::thread
конструктор, как это было перенесено.
Конечно, я хочу иметь контроль над этой функцией, и поэтому я хочу использовать shouldContinue в потоке вызывающего, чтобы остановить вызываемую функцию. По понятным причинам я не хочу делать эту переменную глобальной.
Я думаю что std::ref
делает там немного магии, но я все еще не уверен, как это работает (я видел std::ref
в некоторых примерах при создании новой темы).
Я пытался не заботиться о том, что это ссылка, и я использовал shouldContinue
позже ничего не произошло, но я боюсь, что это просто неопределенное поведение. Может кто-нибудь сказать, если приведенный выше код является правильным, а если нет, как это сделать правильно?
1 ответ
Существует специальное правило вывода типа, когда && используется с шаблонами.
Проверьте это для действительно хорошего объяснения:
http://eli.thegreenplace.net/2014/perfect-forwarding-and-universal-references-in-c/
template <class T>
void func(T&& t) {
}
"Когда && появляется в контексте определения типа, T&& приобретает особое значение. Когда создается экземпляр func, T зависит от того, является ли аргумент, переданный func, lvalue или rvalue. Если это lvalue типа U, T выводится в U&. Если это r-значение, T выводится в U:"
func(4); // 4 is an rvalue: T deduced to int
double d = 3.14;
func(d); // d is an lvalue; T deduced to double&
float f() {...}
func(f()); // f() is an rvalue; T deduced to float
int bar(int i) {
func(i); // i is an lvalue; T deduced to int&
}
Кроме того, правило свертывания ссылок хорошо читается.