将对 main() 中的局部变量的引用传递给其他 threads/functions 不好的做法吗?

Is passing a reference to a local variable in main() to other threads/functions bad practice?

考虑下面的示例,我在 main() 中创建局部变量 specialNumber,并通过引用将其传递给新线程以及另一个函数(请忽略缺少 lock/mutex):

#include <iostream>
#include <thread>

void threadRun(int& number) {
    while(true) {
        std::this_thread::sleep_for(std::chrono::seconds(2));
        std::cout << number << std::endl;
        number += 1;
    }
}

int main() {
    int specialNumber = 5;
    std::thread newThread(threadRun, std::ref(specialNumber));
    otherFunction(specialNumber);
    newThread.join();
}


void otherFunction(int& number) {
    // does something with number
}

我知道通常应该避免传递对局部变量的引用,因为一旦该函数终止,变量将超出范围并且引用将无效。

但是,由于变量是 main() 的局部变量,并且该函数在整个程序终止之前不会终止,这种做法有什么问题吗?

我的具体用例是在此处存储一个小对象(主要由指向堆对象的指针和辅助函数组成),它将被多个线程使用 and/or 函数,并传递一个引用给它。我知道另一种方法是使用 shared_ptr 等智能指针将其存储在堆中,但以这种方式存储这么小的对象对我来说似乎效率低下。

如果我的术语不正确,我深表歉意,我是 C++ 的新手。请纠正我!

你的假设

I am aware that passing references to local variables around should generally be avoided

似乎没有根据。

传递对函数的引用没有错。但是,引用对象的函数不应该拥有该对象的所有权。该函数不应假定引用的对象在退出后继续存在。

这不同于返回对局部变量的引用,后者总是错误的。

我认为传递对线程的引用没有问题(除了缺少同步),这通常比使用全局变量的替代方法更可取。

智能指针,例如 std::shared_ptr,仅当函数应该取得(共享)对象的所有权时才需要,例如如果 threadRun 想在对象退出后保留一个 reference/pointer。

只要 main 线程处于活动状态,您就不会看到出现问题,因为 specialNumber 的生命周期由它控制。

不过我想详细说一下std::ref()的用法。 std::ref() 的用途之一正是您正在编码的场景。

当您使用 std::ref() 时,您实际上返回的是可以复制的 std::reference_wrapper。引用包装器可以存储在容器中,而普通引用则不能。

通过对线程构造函数的引用传递对象是引用包装器发挥作用的方式之一,std::ref() returns 引用包装器。

如果您传递了一个简单的引用,您会看到不同的行为。

阅读更多关于 std::ref() and std::reference_wrapper

这个帖子 How is tr1::reference_wrapper useful? 也很有帮助。