使用移动作为线程向量的自定义分配器

发布于 2024-09-25 06:08:47 字数 737 浏览 11 评论 0原文

我目前正在学习 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

柒夜笙歌凉 2024-10-02 06:08:47

如果您的编译器不提供移动感知的 std::vector 那么您必须编写自己的 std::vector 专门化而不仅仅是提供自定义分配器。整个 C++03 vector 接口依赖于复制: 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 of std::vector<std::thread> rather than just provide a custom allocator. The whole C++03 vector 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 of T()); resize(), reserve(), insert(), erase() and push_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.

我最亲爱的 2024-10-02 06:08:47

规避该问题的最简单方法是在堆上分配线程并操作指向它们的指针。

检查 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.

壹場煙雨 2024-10-02 06:08:47

std 容器仅接受可复制对象的要求更多地与 C++03 容器接口有关,而不是与分配器实现有关。
例如,

vector<T> b(100);
vector<T> a;
a=b;
assert(a==b);

标准向我们保证 a==b 是正确的。但是,如果 T 不可复制,那么在最好的情况下 a=b 将无法编译,在最坏的情况下 a=b 是未定义的。此外,

a.push_back(T());

可能会导致分配新的空间,并且在幕后有从旧的底层存储到新的底层存储的副本。

此外,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

vector<T> b(100);
vector<T> a;
a=b;
assert(a==b);

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,

a.push_back(T());

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文