考虑下面的示例,在该示例中我在specialNumber
中创建局部变量main()
,并通过引用将其传递给新线程以及另一个函数(请忽略缺少锁/互斥体的方式:]
#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()
的局部变量,并且该函数直到整个程序终止后才会终止,所以这种做法有什么问题吗?
我的特定用例将在此处存储一个小对象(主要由指向堆对象的指针以及辅助函数组成),该对象将由多个线程和/或函数使用,并传递对其的引用。我知道一种替代方法是使用诸如shared_ptr
的智能指针将其存储在堆中,但是以这种方式存储如此小的对象对我而言似乎效率低下。
我很抱歉,如果我的任何术语不正确,我对C ++还是陌生的。请纠正我!
您的假设
我知道通常应该避免传递对局部变量的引用
似乎没有根据。
传递对函数的引用没有错。但是,引用对象的函数不应拥有该对象的所有权。该函数不应假定所引用的对象在退出后仍继续存在。
这不同于returning对局部变量的引用,这总是错误的。
我认为传递对线程的引用没有问题(没有同步),这通常优于使用全局变量的替代方法。
[智能指针,例如std::shared_ptr
,仅在假定函数具有对象的(共享)所有权时才需要。如果threadRun
想要在对象退出后保留对其的引用/指针。
只要main()
线程处于活动状态,就不会出现问题。
但是我想详细说明std::ref()
的用法。 std::ref()
的用途之一就是正在编码的场景。
使用std::ref()
时,实际上是在返回可以复制的std::reference_wrapper
。引用包装可以存储在容器中,而普通引用则不能。
通过引用将对象传递给线程的构造函数是使用引用包装器并且std::ref()
返回引用包装器的一种方法。
如果您传递了简单的参考文献,将会看到不同的行为。
阅读有关std::ref()和std::reference_wrapper的更多信息