【发布时间】:2018-05-18 10:36:11
【问题描述】:
不知何故,VC++ (Dinkumware) 上的原生 stl::copy() 算法发现它可以在可简单复制的数据上使用 memcpy()。一个普通人能做到吗? - 假设每个元素都是_trivially_copyable。
random_access_iterator 是否意味着连续内存?标准对我来说不是很清楚。
所以,如果模板中只有一个或两个迭代器,是否有可能在编译时推断出底层数组可以用memcpy() 复制,如果可以的话怎么做?
编辑 - 这是我的动机。我有一个移动数据块而不是复制它的例程。为了在数据可存储时加快速度,我有时将其称为 stl::copy。我想知道这是否是唯一的方法。 (小时候,我总是会在家里尝试这个。)
// Move a range of values
template<class Ptr, class Ptr2>
inline Ptr2 move(Ptr src, Ptr end, Ptr2 dest) {
using value_type = std::iterator_traits<Ptr>::value_type;
if constexpr (std::is_trivially_copyable_v<value_type>) {
return std::copy(src, end, dest);
} else {
while (src != end) {
*dest = std::move(*src);
++src; ++dest;
}
}
return dest;
}
编辑:感谢 zett42 找到这个相关问题:Contiguous iterator detection 我无法解释我是如何错过它的。
编辑更多:在经历了许多曲折的小段落之后,我发现 Dinkum 使用秘密标签作为与人群中的迭代器,例如_Really_trivial_ptr_iterator_tag。所以前景看起来很暗淡。
我的价值 0.02 美元:将 iterator_category 设为 ad-hoc 类型而不是破坏各种特征(如“points_into_contiguous_memory”等)是初学者的错误......因为 random_access_iterator 是仅用标签表示的 ad-hoc 类型,它不能在不破坏遗留应用程序的情况下进行子类型化。所以委员会现在有点卡住了。我说,是时候重新开始了。
哦,好吧。
【问题讨论】:
-
std::vector 的迭代器既是随机访问的,又代表连续的元素。这是根据定义。请注意,调用 memmove 不一定是最快的副本。如果你在 gcc 上使用 -O2 和 -march=native 编译 std::copy,你会得到更好的代码。
-
只有几个contiguous iterator 类型。编译器非常了解它们,并且能够识别何时使用它们并进行所需的优化。
-
假设你不知道迭代器是std::vector。
-
快速浏览一下 MSVC 对
std::copy()的实现,没有编译器魔法可以决定是否可以使用memmove。模板元编程检测连续的迭代器。但这是非标准化的东西,另见Contiguous iterator detection。 -
可能有内部和特定于实现的类型、特征和标签可供算法函数检查。不幸的是,
std::iterator_traits没有连续迭代器的标签。
标签: c++ algorithm templates c++17 memcpy