使用移动作为线程向量的自定义分配器
我目前正在学习 C++ 中的并发性,并遇到了使用线程向量的问题,我相信这在 C++0x 中是可能的。但是,我当前的编译器似乎没有移动感知容器的实现,因此我会生成错误,因为 std::thread::thread(const std::thread&)
被删除,即我只能将移动构造函数/移动赋值与 std::thread
一起使用。
编写自定义分配器来规避这个问题
void MyAllocator::construct (pointer p, reference val)
/* should be non-const reference to val because using move constructor? */
{
new ((void*)p) T (std::move(val));
}
我是否正确地认为我可以通过使用而不是
void allocator::construct (pointer p, const_reference val)
{
new ((void*)p) T (val);
}
?或者这个主题的一些其他变体(可能使用 MyAllocator::construct 的重载)。
注意:这主要是为了进行短期教育练习,并足够好地执行容器中的线程。我只会在这种情况下使用 MyAllocator
。但是,也请向我指出任何可能实现此功能的库,以便我可以查看源代码。
I'm currently learning about concurrency in C++ and came across using a vector of threads, which I believe will be possible in C++0x. However, my current compiler doesn't appear to have an implementation of move-aware containers and so I get errors generated because std::thread::thread(const std::thread&)
is deleted, ie I can only use the move constructor/move assignment with std::thread
.
Am I correct in thinking I could circumvent this issue by writing a custom allocator using
void MyAllocator::construct (pointer p, reference val)
/* should be non-const reference to val because using move constructor? */
{
new ((void*)p) T (std::move(val));
}
rather than
void allocator::construct (pointer p, const_reference val)
{
new ((void*)p) T (val);
}
? Or some other variation on this theme (possibly using an overload of MyAllocator::construct).
NB: This is mainly intended to be a short-term educational exercise and well enough performing work around to play around with threads in containers. I'd only be using MyAllocator
in this context. However, please also point me at any libraries that may have this implemented so I can have a poke around the source.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您的编译器不提供移动感知的
std::vector
那么您必须编写自己的std::vector
专门化而不仅仅是提供自定义分配器。整个 C++03vector
接口依赖于复制:push_back()
复制元素;resize()
使用作为第二个参数传递的元素的副本来初始化空元素(即使这是T()
的默认值>);resize()
、reserve()
、insert()
、erase()
和push_back()如果向量需要重新分配,或者元素需要移动等等,
将复制元素。这是一个非常常见的问题,因此我在我的(商业)just::thread 中包含了这样的专业化
std::thread
的实现。If your compiler doesn't provide a move-aware
std::vector
then you'll have to write your own specialization ofstd::vector<std::thread>
rather than just provide a custom allocator. The whole C++03vector
interface relies on copying:push_back()
copies elements in;resize()
initializes the empty elements with a copy of the element passed as the second parameter (even if that is the default value ofT()
);resize()
,reserve()
,insert()
,erase()
andpush_back()
will copy elements if the vector needs reallocating, or elements otherwise need moving around, and so forth.This is such a common problem that I've included such a specialization with my (commercial) just::thread implementation of
std::thread
.规避该问题的最简单方法是在堆上分配线程并操作指向它们的指针。
检查
Boost Pointer Container
库:boost::ptr_vector
在我看来您正在寻找什么。The easiest way to circumvent the problem would be to allocate the threads on the heap and manipulate pointers to them.
Check the
Boost Pointer Container
library:boost::ptr_vector<std::thread>
seems to me what you are looking for.std 容器仅接受可复制对象的要求更多地与 C++03 容器接口有关,而不是与分配器实现有关。
例如,
标准向我们保证 a==b 是正确的。但是,如果 T 不可复制,那么在最好的情况下 a=b 将无法编译,在最坏的情况下 a=b 是未定义的。此外,
可能会导致分配新的空间,并且在幕后有从旧的底层存储到新的底层存储的副本。
此外,C++03 标准中没有任何内容表明实现实际上必须调用 allocator.construct,而且事实上许多(例如 gcc)不需要调用。
C++0x 标准向可移动类型的容器接口添加了新的成员函数,并阐明了像operator= 这样的东西在它们存在时的行为方式。
参见 www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2486.pdf
The requirement that std containers only take copyable objects has more to do with the C++03 container interfaces than it does with the allocator implementation.
For example
The standard assures us a==b is true. However, if T were not copyable, then in the best case a=b will not compile, in the worst a=b is undefined. Furthermore,
may cause a to allocate new space, and under the hood there are copies made to the new underlying storage from the old.
Furthermore, there is nothing in the C++03 standard that says an implementation actually has to call allocator.construct, and in fact many (gcc for example) do not.
The C++0x standard adds new member functions to the container interface for moveable types, and clarifies how things like operator= behave in their presence.
See www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2486.pdf