求高手解答:C++必经之路 之不确定指针

sumos 2013-09-13 04:28:45
class Hello
{
public:
void run(int c)
{ do_sth(c); }
};

Hello* h = new Hello;
Task* t = Bind(h, &Hello::run); 将类指针及类成员函数封装到一个Task类中
thread->PostTask(t); 将Task投递到线程

问题在:投递线程之后,如果h被delete了,此时线程去执行t的时候就会出错,因为h被删除了。
我的期望:在执行t的时候,先检查h是否还存在,不存在则丢弃该Task。

c++中有一个weak_ptr,弱指针。我知道这个可以解决这个问题,但是如何解决,尝试多次还是没有办法,特此请教高手?
...全文
1052 67 打赏 收藏 转发到动态 举报
写回复
用AI写文章
67 条回复
切换为时间正序
请发表友善的回复…
发表回复
sumos 2015-01-16
  • 打赏
  • 举报
回复
class WeakFlag { private: shared_ptr<WeakFlag> share_ptr_; public: weak_ptr<WeakFlag> GetWeakFalg() { if( share_ptr_.use_count() == 0 ) share_ptr_.reset((WeakFlag*) NULL); return weak_ptr<WeakFlag>(share_ptr_); } }; typedef std::function<void()> StdTask; template<class...Param> std::function<void(Param...)> AttachWeak(std::function<void(Param...)> fun, weak_ptr<WeakFlag> weak) { auto f = [=](Param...p) { if( weak.expired() ) return; fun(p...); }; return f; } class CObj : public WeakFlag { public: StdTask Get() { StdTask f = std::bind(&CObj::Run, this, 5); return AttachWeak(f, GetWeakFalg()); } private: void Run(int c) { printf_s("%d\n", c); } }; void run_test() { CObj* o = new CObj; StdTask f = o->Get(); delete o; f(); }
sumos 2013-10-31
  • 打赏
  • 举报
回复
引用 65 楼 superzmy 的回复:
我的做法唯一缺点是数组的长度是固定的,当然我现在用的是静态数组 改改也可以变成动态的
你说的也是很对的。一般一个工程,即使很大,用到成员函数作为回调的对象也不会太多,哪怕十万个,一个set可以轻松保存。
superzmy凄临雨 2013-10-31
  • 打赏
  • 举报
回复
我的做法唯一缺点是数组的长度是固定的,当然我现在用的是静态数组 改改也可以变成动态的
superzmy凄临雨 2013-10-31
  • 打赏
  • 举报
回复
引用 63 楼 superzmy 的回复:
楼主你这个东西跟我网络层的连接对象删除一摸一样,之前用shareptr给气死 因为这货不能阻止删除,多线程表现也很烂 我是这么做的,用静态数组、句柄实现,句柄=(编号,循环码) 投递的时候给的那个句柄,可以自校验对象有没有被删除 可以无锁编程 只要编号就能确定内存位置,用循环码确定对象是否是句柄表示的那个对象 效率很高,代码很变态
实践证明我的做法比智能指针强多了, 我实现的这东西可以删除,可以阻止删除(删除时遇到某些事件以后取消删除),可以有锁定状态(阻塞取对象操作) 不需要调用系统锁(只要所以操作都能迅速解除锁状态)
superzmy凄临雨 2013-10-31
  • 打赏
  • 举报
回复
楼主你这个东西跟我网络层的连接对象删除一摸一样,之前用shareptr给气死 因为这货不能阻止删除,多线程表现也很烂 我是这么做的,用静态数组、句柄实现,句柄=(编号,循环码) 投递的时候给的那个句柄,可以自校验对象有没有被删除 可以无锁编程 只要编号就能确定内存位置,用循环码确定对象是否是句柄表示的那个对象 效率很高,代码很变态
newzai 2013-10-30
  • 打赏
  • 举报
回复
引用 58 楼 zhoujielunzhimi 的回复:
[quote=引用 56 楼 boyka913 的回复:] 学习一下智能指针吧
引用 57 楼 chenxiaohong3905 的回复:
智能指针可以解决此问题。。。
给个例子啊[/quote] 例子吗,自己想办法,相信你了解了智能指针后,会知道如何解决这个问题的。。
mindblast 2013-10-30
  • 打赏
  • 举报
回复

class Task
{
public:
virtual void Run() = 0;
};

template <class T, class M>
class Task0 : public Task
{
private:
weak_ptr<T> t;	M m;
public:
Task0(T* _t, M _m) : t(_t), m(_m) {}
virtual void Run()
{
shared_ptr<T> p = t.lock();
if (p)
   (p->*m)();
else
   printf("task cancelled!")
}
};

template <class T, class M>
Task* Bind(T* t, M m)
{
return new Task0<T,M>(t, m);
}

class Hello
{
public:
   void show(){  cout<<"hello"; }
};

shared_ptr<Hello> h(new Hello);
Task* t = Bind(h, &Hello::show);
大概是这个样子,你自己再测测吧
newzai 2013-10-30
  • 打赏
  • 举报
回复
引用 60 楼 zhoujielunzhimi 的回复:
[quote=引用 59 楼 chenxiaohong3905 的回复:] [quote=引用 58 楼 zhoujielunzhimi 的回复:] [quote=引用 56 楼 boyka913 的回复:] 学习一下智能指针吧
引用 57 楼 chenxiaohong3905 的回复:
智能指针可以解决此问题。。。
给个例子啊[/quote] 例子吗,自己想办法,相信你了解了智能指针后,会知道如何解决这个问题的。。 [/quote] 你看我之前的回复,我对shared_ptr和weak_ptr已经了解了,只是解决我的问题,我使用的是shared_ptr->reset()来删除对象,暂时没法做到delete来直接删除。[/quote] shared_prt和weak_ptr配合使用。通过weak_ptr进行检测对象是否已经被删除。如果对象被删除则不进入方法调用。 还有,你可以不使用bind方法,而是通过 闭包捕获对象。。。 shared_ptr<Hello> sp( new Hello); weak_ptr<Hello> wp(sp); Task * t = [wp](){ if( !wp.expired()){ //对象存在,,,调用 wp.lock()->run() }else{ //对象已经删除 } } 自己想办法,把闭包转换为Task对象。。。。bind可以,闭包一样可以。。。
sumos 2013-10-30
  • 打赏
  • 举报
回复
引用 59 楼 chenxiaohong3905 的回复:
[quote=引用 58 楼 zhoujielunzhimi 的回复:] [quote=引用 56 楼 boyka913 的回复:] 学习一下智能指针吧
引用 57 楼 chenxiaohong3905 的回复:
智能指针可以解决此问题。。。
给个例子啊[/quote] 例子吗,自己想办法,相信你了解了智能指针后,会知道如何解决这个问题的。。 [/quote] 你看我之前的回复,我对shared_ptr和weak_ptr已经了解了,只是解决我的问题,我使用的是shared_ptr->reset()来删除对象,暂时没法做到delete来直接删除。
boyka913 2013-10-29
  • 打赏
  • 举报
回复
学习一下智能指针吧
sumos 2013-10-29
  • 打赏
  • 举报
回复
引用 56 楼 boyka913 的回复:
学习一下智能指针吧
引用 57 楼 chenxiaohong3905 的回复:
智能指针可以解决此问题。。。
给个例子啊
newzai 2013-10-29
  • 打赏
  • 举报
回复
智能指针可以解决此问题。。。
  • 打赏
  • 举报
回复
引用 54 楼 zhoujielunzhimi 的回复:
[quote=引用 53 楼 CKnightx 的回复:] 能不能自己维护一个Task队列,当h被delete之前,去update一下这个队列,把h相关的Task移除,然后delete h。 我才你的线程执行的时候,也是去轮循Task队列,找到相关的task然后调用你bind的回调的吧。
你这种方法也是可行的。毕竟要绑定 成员函数 的类 的对象也不会很多,所以维护一个map是绝对没有问题的。 这个问题的解决方法其实是很多的,但是weak_ptr是最巧妙的,因为这是c++11新的标准。[/quote] 其实主要问题还是在RTTI上,引用了h却没有给增加h的引用计数。你可以尝试写一个智能指针的类,去wrap一下h这个对象。然后post到task上。 weak_ptr指针,还是先不要用于商用吧。首先,不是所有的编译器都支持了,其次,C++11到商用,还是需要一段时间磨合的。
sumos 2013-10-25
  • 打赏
  • 举报
回复
引用 53 楼 CKnightx 的回复:
能不能自己维护一个Task队列,当h被delete之前,去update一下这个队列,把h相关的Task移除,然后delete h。 我才你的线程执行的时候,也是去轮循Task队列,找到相关的task然后调用你bind的回调的吧。
你这种方法也是可行的。毕竟要绑定 成员函数 的类 的对象也不会很多,所以维护一个map是绝对没有问题的。 这个问题的解决方法其实是很多的,但是weak_ptr是最巧妙的,因为这是c++11新的标准。
  • 打赏
  • 举报
回复
能不能自己维护一个Task队列,当h被delete之前,去update一下这个队列,把h相关的Task移除,然后delete h。 我才你的线程执行的时候,也是去轮循Task队列,找到相关的task然后调用你bind的回调的吧。
sumos 2013-10-24
  • 打赏
  • 举报
回复
引用 51 楼 sdu20112013 的回复:
额。。。没看懂....h被delete了后h不是要赋空么.....执行任务前检查一下h是不是空不就好了?
跨线程的情况。 UI框架中在OnDestroy中都会delete this,但任务早就跑到 逻辑线程了,逻辑线程执行时,怎么知道这个form被delete了呢 weak_ptr就可以完成,当form被delete后,weak_ptr中的引用就无效了,所以此时判断weak_ptr就行了
赵4老师 2013-10-23
  • 打赏
  • 举报
回复
其实电脑开机后物理内存的每个字节都是可读写的,区别仅在于操作系统内存管理模块在你读写时是否能发现并是否采取相应动作而已。操作系统管理内存的粒度不是字节而是页,一页通常为4KB。
WillBeFreeeee 2013-10-23
  • 打赏
  • 举报
回复
额。。。没看懂....h被delete了后h不是要赋空么.....执行任务前检查一下h是不是空不就好了?
边走边瞧 2013-10-22
  • 打赏
  • 举报
回复
使用win32API——IsBadReadPtr,还有比这更无耻的做法没?
zhaokai115 2013-10-22
  • 打赏
  • 举报
回复
引用 楼主 zhoujielunzhimi 的回复:
class Hello { public: void run(int c) { do_sth(c); } }; Hello* h = new Hello; Task* t = Bind(h, &Hello::run); 将类指针及类成员函数封装到一个Task类中 thread->PostTask(t); 将Task投递到线程 问题在:投递线程之后,如果h被delete了,此时线程去执行t的时候就会出错,因为h被删除了。 我的期望:在执行t的时候,先检查h是否还存在,不存在则丢弃该Task。 c++中有一个weak_ptr,弱指针。我知道这个可以解决这个问题,但是如何解决,尝试多次还是没有办法,特此请教高手?
主线程向子线程发消息,子线程收到消息后自己delete h,这样比较安全。如果主线程也需要访问h,子线程要回消息给主线程,主线程收到消息后标记h=NULL。
加载更多回复(46)

64,654

社区成员

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

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