鉴于std::copy(显然对于普通类型)只能作为memmove (*)的包装器实现,我想知道:
memcpy?(我数不清忘记乘以的次数sizeof。)memcpy进行sizeof乘法的包装器是否有任何特定障碍?(*):C++ 标准库实现(从 MSVC 2005(!) 到现代 MSVC2015、libc++ 等)将 TriviallyCopyablestd::copy类型衰减为memmove. 博特不来memcpy。因为:
std::copy(src_first, src_last, destination_first) 定义:
如果
d_first在范围内,则行为未定义[first, last)。
d_first可以在源范围的“左边”,而目标范围可以扩展到源范围内。因为std::memcpy定义是
如果对象重叠,则行为未定义。
对于std::memmove,定义为:
对象可能会重叠:复制的发生就像将字符复制到临时字符数组,然后将字符从数组复制到 dest。
鉴于此,很明显您可以使用std::memove实现std::copyTrivialllyCopyable 类型,因为 memmove 没有强加任何限制,并且可以在编译时通过类型特征分派到正确的实现——
但是很难实现std::copy,memcpy因为 (a) 检查指针范围是否重叠必须在运行时完成,以及 (b) 甚至对不相关的内存范围实施运行时检查可能会非常混乱。
所以,这给我们留下了
void* memcpy( void* dest, const void* src, std::size_t count );
Run Code Online (Sandbox Code Playgroud)
一个接口不那么出色的函数,您经常需要将非字符对象的输入计数与其相乘,sizeof而这是完全无类型的。
但是 memcpy 是最快的(并且有很大的差距,请自行测量),并且当您需要 TriviallyCopyable 类型的快速副本时,您可以使用 memcpy。从表面上看,这应该很容易包装在类型安全的包装器中,例如:
template<typename T>
T* trivial_copy(T* dest, T* src, std::size_t n) {
return static_cast<T*>(std::memcpy(dest, src, sizeof(T) * n));
}
Run Code Online (Sandbox Code Playgroud)
但是,不清楚您是否应该通过std::is_trival或其他方式进行编译时检查,当然可能会有一些讨论是否使用确切的memcpy签名顺序,yadda yadda。
那么我真的必须自己重新发明这个轮子吗?是否为标准进行了讨论?等等。
为了澄清 mencpy 和 memove 之间的区别,根据文档 memmove 可以将内存复制到与源内存重叠的位置,对于 memcpy 来说这是未定义的行为。
“对象可能重叠:复制的发生就好像将字符复制到临时字符数组,然后将字符从数组复制到目标。 ”
当您需要 memcpy 时,是否有标准 C++ 类型安全包装器?(我已经数不清有多少次忘记乘以 sizeof 了。)
是的,std::copy(也许,解释如下)
如果标准中没有任何内容,是否有任何建议?如果没有,为什么不呢?
据我所知,该标准并不强制对普通类型的 std::copy 使用 memmove/memcpy 。所以就看实施了。例如,在Visual Studio update 2015 update 2 中,他们确实使用 memmove 来加快速度:
“提高了 std::vector 重新分配和 std::copy() 的速度;当它们为普通可复制类型(包括用户定义类型)调用 memmove() 时,速度提高了 9 倍。 ”
提供自动执行 sizeof 乘法的 memcpy 包装器是否有任何特定障碍?
不,事实上您可以使用std::is_trivial自己实现
编辑:
根据本文档第 25.3.1 节,对 std::copy 实现没有任何限制,只有复杂性:
复杂性:恰好是最后 - 第一个作业。
当您考虑到 memcpy 使用 cpu 特定指令(并非在所有 cpu 上都可用)来加速内存复制时,这是非常有意义的。
| 归档时间: |
|
| 查看次数: |
1288 次 |
| 最近记录: |