鉴于 std::copy
(显然仅适用于 Trivial Types)只能作为 memmove(*) 的包装器实现,我想知道:
- 是否有标准的 C++ 类型安全的包装器可用于需要使用
memcpy
的情况?(我数不清有多少次忘记乘以sizeof
。) - 如果标准中没有这样的东西,是否有任何提案?如果没有,为什么没有?
- 是否存在特定的障碍,使得提供一个自动执行
sizeof
乘法的memcpy
包装器成为不可能?
(*): C++标准库实现(从MSVC 2005开始,一直到现代的MSVC2015、libc++等)将TriviallyCopyable类型的std::copy
衰减为memmove
。但不是memcpy
。原因是:
std::copy(src_first, src_last, destination_first)
的定义如下:如果
d_first
在范围[first, last)
内,则行为未定义。- 只有目标范围的开头不允许在源范围内。目标范围可以延伸到源范围内。也就是说,
d_first
可以在源范围的“左侧”,并且目标范围可以延伸到源范围内。
- 只有目标范围的开头不允许在源范围内。目标范围可以延伸到源范围内。也就是说,
对于
std::memcpy
,定义如下:如果对象重叠,则行为未定义。
- 也就是说,完整的范围不能重叠:这就是使 memcpy 成为最快变体的原因,因为它可以假定源和目标的内存完全不同。
对于
std::memmove
,定义如下:对象可能重叠:复制的过程就像将字符复制到临时字符数组中,然后从数组中将字符复制到 dest 中一样。
- 也就是说,源范围和目标范围可以任意重叠,没有限制。
std::memove
来实现std::copy
,因为memmove不会强制执行任何限制,并且通过类型特征可以在编译时分派到正确的实现。但是,使用memcpy
来实现std::copy
很难,因为(a)检查指针范围是否重叠必须在运行时进行,(b)即使对于无关的内存范围实现运行时检查可能会非常混乱。因此,这让我们只能void* memcpy( void* dest, const void* src, std::size_t count );
一个界面不太好的函数,你需要不断地将非字符对象的输入计数与它们的
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));
}
但是,现在还不清楚是否应该通过std::is_trival
等方式进行编译时检查,当然也可能会有一些讨论,例如是否要使用确切的memcpy
签名顺序等等。
那么,我真的需要自己重新发明这个轮子吗?它是否被讨论过用于标准库中?等等。
std::copy
必须由memmove
实现? - nwpstd::copy
本身? - Mikhailmemmove
”,而是“不能使用memcpy
,只能使用memmove
”。 - user743382std::copy
的文档说明:“如果源范围和目标范围重叠,则行为未定义。”,这使它可以退化为memcpy
。 - Mikhailstd::copy
,范围允许重叠,只要目标范围的开头不在源范围内即可。 - Martin Ba