移动线程对象后应该把旧线程对象设置成什么呀

z416575462 2017-12-09 12:44:06
我照着书上写了一个scoped_thread类,用来管理线程对象,
每个scoped_thread都存了一个thread对象,用于当程序销毁scoped_thread对象时,
将会在析构函数中调用thread对象的join以便等待线程执行完毕,如下:

#include <thread>
#include <stdexcept>
#include <iostream>
class scoped_thread {
std::thread t;
public:
explicit scoped_thread(std::thread && t_) :t(std::move(t_)) {
if (!t.joinable())
throw std::logic_error("No thread");
}
~scoped_thread() {
t.join();
std::cout << "destruct a thread" << std::endl;
}
scoped_thread(scoped_thread const &) = delete;
scoped_thread& operator=(scoped_thread const &) = delete;
//这下面的是我自己写的,没写完。移动构造器
scoped_thread(scoped_thread && t_) noexcept:t(std::move(t_.t)) { //t_.t = ;不会写了。。
}
//移动赋值运算符,也没写玩,不会写
scoped_thread& operator=(scoped_thread && t_) = default;

};

然后,书上的调用类似这样的:

void funruninthread(){cout<<"hi"<<endl;}
void f(){
scoped_thread st{thread(funruninthread)};
}//这样在函数结束时会自动等待线程执行完毕

,后来,又介绍了把thread对象放入vector中,由此,我就想到了能不能把scoped_thread对象放入vector中呢?
然后我就发现。了一个问题:

vector<scoped_thread> vst;

1,当我往vst中放入scoped_thread对象时,如果vst旧空间不足,会扩容,
然后把容器内的旧空间内的对象挪动到新空间里。然后销毁旧空间。
(就是那个移动构造器和移动赋值运算符那我不会写。。。)
,这样挪动过程好像就会调用scoped_thread对象的析构函数导致线程join,然后新空间中的线程就变成不能join了,这样好像以后真正析构vector容器时就不能再join这个对象了。
如果我写一个移动赋值运算符函数,把一个scoped_thread对象移动给另一个对象后,如何设置旧的scoped_thread对象内的thread成员?让它是一个可以join()的(这样旧的对象也可以析构),但析构又不会影响新scoped_thread的对象呢??
...全文
123 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
z416575462 2017-12-10
  • 打赏
  • 举报
回复
引用 11 楼 hdt 的回复:
[quote=引用 10 楼 z416575462 的回复:] [quote=引用 6 楼 hdt 的回复:] [quote=引用 5 楼 z416575462 的回复:] 如果写成vector<scoped_thread&> vst 那这样好像scoped_thread对象不是由vector统一管理了。感觉好像外面一份,vector内又有个引用。
恰恰相反,vecort<scoped_thread>才是两份。[/quote] 我把拷贝构造器和拷贝赋值运算符都删除了,容器好像不会存两份的。[/quote]删除是不管用的,当你不提供的时候编译器会自动为每个类添加拷贝构造和复制。 你可以把拷贝构造和赋值定义为私有的,就清楚了[/quote] 我是这样删除的:
 
scoped_thread(scoped_thread const &) = delete;
scoped_thread& operator=(scoped_thread const &) = delete;
真相重于对错 2017-12-09
  • 打赏
  • 举报
回复
嗯 存引用确实在生存期控制会有一些问题 那就变成存指针
真相重于对错 2017-12-09
  • 打赏
  • 举报
回复
引用 7 楼 xsklld 的回复:
[quote=引用 2 楼 hdt 的回复:] 试试 vector<scoped_thread&> vst;
容器里存引用要用std::ref包装。[/quote]真的???
真相重于对错 2017-12-09
  • 打赏
  • 举报
回复
引用 10 楼 z416575462 的回复:
[quote=引用 6 楼 hdt 的回复:] [quote=引用 5 楼 z416575462 的回复:] 如果写成vector<scoped_thread&> vst 那这样好像scoped_thread对象不是由vector统一管理了。感觉好像外面一份,vector内又有个引用。
恰恰相反,vecort<scoped_thread>才是两份。[/quote] 我把拷贝构造器和拷贝赋值运算符都删除了,容器好像不会存两份的。[/quote]删除是不管用的,当你不提供的时候编译器会自动为每个类添加拷贝构造和复制。 你可以把拷贝构造和赋值定义为私有的,就清楚了
z416575462 2017-12-09
  • 打赏
  • 举报
回复
引用 6 楼 hdt 的回复:
[quote=引用 5 楼 z416575462 的回复:] 如果写成vector<scoped_thread&> vst 那这样好像scoped_thread对象不是由vector统一管理了。感觉好像外面一份,vector内又有个引用。
恰恰相反,vecort<scoped_thread>才是两份。[/quote] 我把拷贝构造器和拷贝赋值运算符都删除了,容器好像不会存两份的。
z416575462 2017-12-09
  • 打赏
  • 举报
回复
我自己想了个办法:增加一个bool成员。 在析构的时候判断一下,如果为真才join, 而在移动构造器里,移动后把旧对象的该成员设置为假。 就好了
xskxzr 2017-12-09
  • 打赏
  • 举报
回复
引用 2 楼 hdt 的回复:
试试 vector<scoped_thread&> vst;
容器里存引用要用std::ref包装。
真相重于对错 2017-12-09
  • 打赏
  • 举报
回复
引用 5 楼 z416575462 的回复:
如果写成vector<scoped_thread&> vst 那这样好像scoped_thread对象不是由vector统一管理了。感觉好像外面一份,vector内又有个引用。
恰恰相反,vecort<scoped_thread>才是两份。
z416575462 2017-12-09
  • 打赏
  • 举报
回复
如果写成vector<scoped_thread&> vst 那这样好像scoped_thread对象不是由vector统一管理了。感觉好像外面一份,vector内又有个引用。
z416575462 2017-12-09
  • 打赏
  • 举报
回复
可是我并不希望在容器扩容的时候等待容器中的所有线程啊。 我只是希望容器扩容归扩容, 而等待所有线程都放到容器销毁的那一刻才等待线程。
真相重于对错 2017-12-09
  • 打赏
  • 举报
回复
你这么想。 比如你邀请了一堆富翁,比如马云,王建玲都来了 可以把一间房子,想成vector, 让马云他们都尽了这间房子,那么这间房子之外,还会有马云他们吗? 当然,也可能有个邪恶的科学家,发明了复制机器,临时复制了一堆小马云。。。。等他们一进入那间房子,立刻用假的夺了他们的财产。 当然以上,都是我模仿某个低劣的科幻小说的瞎想
真相重于对错 2017-12-09
  • 打赏
  • 举报
回复
试试 vector<scoped_thread&> vst;
xskxzr 2017-12-09
  • 打赏
  • 举报
回复
把t.join()包一层try catch就行了。 如果t被移动过,标准保证执行t.join()会抛system_error。可以参考这个例子

64,651

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧