Почему нам не разрешено передавать чистые ссылочные аргументы в std :: thread, но мы можем передавать необработанные указатели? - PullRequest
2 голосов
/ 12 октября 2019

Допустим, я хочу передать некоторый ссылочный аргумент в поток - стандарт допускает это только с помощью std::ref.

Теперь давайте рассмотрим этот код с неопределенным поведением (см. Комментарии)

    void thread_fun(int& x) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        x = -2;
    }

    int main() {
        {
            int a = 10;
            std::thread t(thread_fun, std::ref(a));
            std::cout << "in main: " << a << '\n';
            t.detach();
        }
        // here thread t may still running and writing to an object "a" which
        // already destroyed is undefined behaviour
        return 0;
    }

Без использования std :: ref (a) он не компилируется - это какая-то защита от неопределенного поведения во время компиляции?

Если это так, то для меня большой вопрос , почему нам разрешено передавать необработанные указатели в std :: thread?

Например, я могу переписатьтот же код выше для передачи указателя, например, так:

    void thread_fun(int* x) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        *x = -2;
    }
    //...
    {
        int a = 10;
        std::thread t(thread_fun, &a);
        //...
    }

И это также содержит неопределенное поведение, но здесь нет защиты во время компиляции!?

Что особенного в случае передачи ссылок ??

Ответы [ 2 ]

1 голос
/ 12 октября 2019

Что особенного в случае передачи ссылок ??

Особенность в том, что передача по ссылке на сайте вызова выглядит идентично передаче по значению.

Каждый показанный вами случай оставляет хотя бы подсказку на сайте вызова, которую выможет делать что-то рискованное, не читая прототип функции.

0 голосов
/ 13 октября 2019

это какая-то защита от неопределенного поведения во время компиляции?

Нет, по умолчанию поток принимает аргументы в качестве копий (или перемещается)

Аргументы функции потока перемещаются или копируются по значению. Если в функцию потока необходимо передать ссылочный аргумент, его необходимо обернуть (например, с помощью std :: ref или std :: cref). https://en.cppreference.com/w/cpp/thread/thread/thread

Таким образом, как указано, ссылки должны каким-то образом «показываться».

Указатель не обрабатывается по-разному, он просто копируется.

Неопределенное поведение здесь не перехватывается компилятором (enven, если возможно может), потому что использование ссылки не всегда означает неопределенное поведение здесь, в зависимости от вашей конструкции (если вы не отсоединяете, а присоединяетесь, это будетвсе будет в порядке).

Это то же самое для указателя, оно может исходить от глобального или нового, что будет в порядке.

...