我可以编译以下代码:
void threadFunc(Vec3f *&buffer) {}
...
std::unique_ptr<Vec3f []> buffer(new Vec3f[100]);
Vec3f *b = buffer.get();
std::thread(threadFunc, std::ref(b)).join();
但是我不能编译:
std::thread(threadFunc, std::ref(buffer.get())).join();
我在编译时得到以下错误:
error: use of deleted function ‘void std::ref(const _Tp&&) [with _Tp = Vec3<float>*]’
编辑:在unique_ptr超出作用域之前,线程已经加入了
两个版本有什么不同?我能让第二个解决方案起作用吗?
此外,通过引用传递指向托管对象的指针似乎比通过引用传递unique_ptr本身更好(threadFunc只需要修改buffer
的内容)。比如:
void threadFunc(std::unique_ptr<Vec3f []> &ptr) {}
std::thread(threadFunc, std::ref(buffer)).join();
这是不好的做法吗?或者这也可以接受吗?在我看来,如果我想改变缓冲区的内容,这是我应该传递给线程函数,而不是unique_ptr本身?如有任何建议,不胜感激。
<标题>编辑2:所以根据下面的一个答案,第二个选项是不可能的,因为std::ref(buffer.get())
使用一些临时对象。尽管第一个版本不管说什么应该工作(我不明白为什么这将是无效的):
Vec3f *tmp = new Vec3f[100];
std::unique_ptr<Vec3f []> buffer = std::unique_ptr<Vec3f []>(tmp);
Vec3f *b = buffet.get(); // address of b == address of tmp
std::thread(threadFunc, std::ref(b));
一样:
std::thread(threadFunc, std::ref(tmp));
对于提供的解决方案:
void threadFunc(Vec3f *buffer) { buffer[0] = 0; // invalid }
Vec3f *buffer = new Vec3f[100];
std::thread(threadFunc, buffer);
这对我来说似乎是无效的,因为buffer
是通过值传递的,而不是通过引用,但是我需要写入缓冲区。所以它需要通过ref.
它不起作用的原因是因为您试图获得对临时对象的引用。你不能这样做,因为它里面的reference_wrapper只有指针,它拒绝保存指向临时对象的指针。很可能编译的版本实际上是错误的,因为您正在传递指向托管对象的指针,该指针可能在其他线程中使用时被删除(除非线程在unique_ptr超出作用域之前加入)
顺便说一下,unique_ptr的设计就是为了让你从这些烦恼中解脱出来。只需按值传递unique_ptr,让另一个线程管理它的生命周期。 编辑:从我们的讨论中,似乎线程是在unique_ptr超出作用域之前连接的。如果我的理解是正确的,您根本不需要为线程函数提供unique_ptr。下面是一个非常好的(伪)代码:typedef <your type> type_t;
void handle_func(type_t* ptr);
typedef std::unique_ptr<type_t> ptr_t;
ptr_t ptr(new type_t);
std::thread handler(handle_func, ptr.get());
handler.join();
另一方面,从上面的代码片段中甚至不清楚为什么需要unique_ptr——而不是简单地使用局部变量并向其传递地址或ref()。我想,有我不知道的原因。