将许多向量累积到一个容器中,无需复制

Accumulating many vectors into a single container w/o copying

本文关键字:一个 复制 向量 许多      更新时间:2023-10-16
是否可以

在 C++11 中将许多std::vector累积到一个std容器中,每个都由给定的函数(我无法更改其 API)返回,而无需复制任何元素?

std::vector<int> make_vect();
container acc;                           // what is container?
do {
    acc.append(std::move(make_vect()));  // how to implement this?
} while(acc.size() < n);

注意 1,即使元素没有移动赋值运算符的移动构造函数,例如示例中的 int,也不得复制这些元素。因此,您可以移动元素块(通过复制指针),但不能移动单个元素。

注意 2container必须允许使用单个迭代器迭代所有累积元素。所以std::vector<std::vector<>>或类似的是不允许的。

显然,编写一些允许这样做的容器或使用std::list<std::vector<>>并提供自己的迭代器是很简单的,但是std库是否在没有此类用户编写的添加的情况下提供了所需的功能?

似乎请求的功能没有什么特别古怪的,我很惊讶即使使用 C++11 也很难(如果不是不可能的话)。

TL;DR 我不认为库存标准容器可以做到你的要求。原因如下。

请记住,容器的移动语义是有效的,因为它们是作为动态分配的内存的作用域绑定句柄实现的。移动容器实现为复制句柄,同时不接触包含的元素。

您的第一个(显式)约束是不复制任何容器的任何元素。这需要将句柄复制到您推定的acc_container中。换句话说,你想要一个acc_container<std::vector<T>>。任何标准容器都可以让您有效地做到这一点,无论单个元素T有多大。

您的第二个(隐含的,从注释中推断)约束是您希望在所有单个向量的所有元素上具有统一的接口。换句话说,您想将其用作 acc_container<T> .这需要在acc_container的迭代器中增加额外的间接寻址,迭代器检测到它已到达当前vector<T>之一的末尾,并跳转到下一个vector<T>的开头。

标准库中不存在此类容器。

最简单的解决方法是使用std::vector<std::vector<T>>(以避免复制T元素),并编写自己的迭代器适配器(例如,使用 boost::indirect_iterator ,以提供对T元素的迭代)。

不幸的是,即使您提供了从成员.begin()/.end()初始化这些间接迭代器的非成员begin()/end()函数,range-for 也不会使用 ADL 来查找这些函数,因为它会更喜欢旧成员函数.begin()/.end()。此外,您将无法例如 将T元素直接insert()到复合容器中,除非您还提供了非成员insert()(以及其他类似功能)。

因此,如果你想要一个真正的复合容器,具有范围支持和成员函数的本机接口,你需要自己编写一个(std::vector<std::vector<T>作为后端,整个std::vector<T>接口写在它上面)。也许你可以在Boost邮件列表中推荐它作为一个不错的项目。

更新:这是Matt Austern关于分段迭代器和分层算法的旧论文的链接,该论文显示了这种方法的一些性能优势。缺点是你还需要让标准算法知道这些迭代器。