C++并发:线程函数传参(二)

正文

传参中的陷阱

1. 向std::thread 构造函数传参:所有参数(含第1个参数可调用对象)均按值并以副本的形式保存在 std::thread 对象中的tuple里。这一点的实现类似于std::bind如果要达到按引用传参的效果,可使用std::ref来传递

2. 向线程函数的传参:由于std::thread 对象里保存的是参数的副本,为了效率同时兼顾一些只移动类型的对象,所有的副本均被std::move到线程函数,即以右值的形式传入

注意事项

1. 一个实参从主线程传递到子线程的线程函数中,需要经过两次传递。第1次发生在 std::thread 构造时,此次参数按值并以副本形式被保存。第2次发生在向线程函数传递时,此次传递是由子线程发起,并将之前std::thread内部保存的副本以右值的形式(std::move())传入线程函数中的。

2. 如果线程函数的形参为T、const T&或T&&类型时,std::thread的构造函数可以接受左值或右值实参。因为不管是左值还是右值,在std::thread中均是以副本形式被保存,并在第2次向线程函数传参时以右值方式传入,而以上三种形参均可接受右值。

3. 而如果线程函数的形参为T&时,不管是左值还是右值的T类型实参,都是无法直接经std::thread传递给形参为T&的线程函数,因为该实参数的副本会被std::move成右值并传递线程函数,但T&无法接受右值类型。因此,需要以std::ref形式传入

4. 当向线程函数传参时,可能发生隐式类型转换,这种转换是在子线程中进行的。需要注意,由于隐式转换会构造临时对象,并将该对象(是个右值)传入线程函数,因此线程函数的形参应该是可接受右值类型的T、const T&或T&&类型,但不能是T&类型。此外,如果源类型是指针或引用类型时,还要防止可能发生悬空指针和悬空引用的现象。
 
上面需要注意的第4 点中谈到,这种隐式转换可能会产生临时对象。在之前的描述中关于 std::reference_wrapper 的隐式类型转换,并不涉及临时对象的构造。这里的隐式转换不创建新的对象,而是提供对已存在对象的引用

我将进一步解释这一点:

std::reference_wrapper 和隐式类型转换

std::reference_wrapper<T> 实现隐式类型转换操作符(operator T&() const),它并不创建新的 T 类型的对象。相反,它返回它所包装的现有对象的引用。这是一个重要的区别,因为返回引用意味着没有新对象的构造,只是提供对原始对象的直接访问

何时会发生临时对象的构造

临时对象的构造通常发生在如下情况:

  • 当函数返回一个非引用类型的值时。
  • 当创建一个新对象,并使用另一个对象来初始化它时(如复制或移动构造函数调用)。
  • 当类型转换需要创建一个新的类型实例时(如从一种复杂类型到另一种类型的转换,如果没有直接的引用传递路径)。

std::reference_wrapper 使用的上下文中:

  • 不会 创建新的 T 类型的对象,因为类型转换操作符返回的是一个已经存在的对象的引用

结论

因此,在使用 std::reference_wrapper 时,与其隐式转换相关的操作只是提供一个现有对象的引用,而不是创建一个新的对象。这保证了效率和引用的正确传递,是在多线程编程中安全使用对象引用的有效方式。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值