为什么我们不允许将纯引用参数传递给 std::thread 但允许传递原始指针?

Why are we not allowed to pass pure reference arguments to std::thread but are allowed to pass raw pointers?

假设我想将一些引用参数传递给线程——标准只允许使用 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);
        //...
    }

这也包含未定义的行为,但这里没有编译时保护!?

传递引用有什么特别之处??

What is special in case of passing references ??

特别之处在于,按引用传递在调用点看起来与按值传递相同。

您展示的每个其他案例至少会在调用站点留下一个提示,表明您可能正在做一些有风险的事情,而无需阅读函数原型。

is this some kind protection from undefined behaviour at compile time ?

不是,默认情况下线程将参数作为副本(或移动)

The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g. with std::ref or std::cref). https://en.cppreference.com/w/cpp/thread/thread/thread

因此,正如所指出的,引用需要以某种方式 "shown"。

指针没有区别对待,它们只是被复制了。

这里未定义的行为没有被编译器捕获(即使 可能 它可以)因为使用引用并不总是意味着这里的未定义行为,这取决于你构造(如果你不要分离,但加入,就可以了)。

指针也一样,它可能来自一个全局的或者一个新的都可以。