std::copy_n 是否适用于重叠范围?



我在 N3485 25.3.1 [alg.copy] 上查找了 C++ 标准,它定义了 4 种算法:

  • copy
  • copy_backward
  • copy_if
  • copy_n

copy的描述中,有这样的注释 25.3.1 [alg.copy]/3:

要求:结果不得在[首、末一]范围内

也就是说,当范围重叠时,copy并不总是正常工作(类似于memcpy)。

copy_backwardcopy_if具有类似的语言,禁止重叠范围(分别为25.3.1 [alg.copy]/14和25.3.1 [alg.copy]/8)。

但是,对copy_n没有这样的禁令,也没有copy_n_backward。这是否意味着当范围重叠时,copy_n做了正确的事情?

(MSVC++的copy_n实现似乎委托给std::memmove,所以我知道它在MSVC++ 2013上是安全的。但如果标准另有暗示,我不想依赖这个)

它是安全的*。为什么?因为标准没有说它不安全。他们从 25.3.1 复制函数有Requires:对于他们需要的东西(这是在其他复制表单中说明重叠禁止的地方)。

但是,copy_n并没有说它要求范围不重叠,这意味着没关系,因为它没有明确禁止。如果它需要它,它会说明它。

*编辑:当我的意思是"安全"时,我的意思是它不是未定义的行为或格式错误的程序。但是,如果内存范围重叠,则不能保证结果是您可能想要的结果。我们唯一可以保证的是:

  1. 对于每个非负整数i < n,执行*(result + i) = *(first + i)
  2. 不禁止使用重叠范围调用函数,并且不会导致未定义的行为。

因此,我们可以推断,如果范围重叠,则存储在目标中的结果不再保证是源的精确(按顺序)副本。我们保证目标中的每个值都来自源,尽管这些值的确切位置取决于重叠和复制元素的确切顺序。

因此,如果您所说的"安全"是指目的地始终具有源的完美副本(如memmove),那么不,它不是"安全的"。但它是安全的,因为它本身不会导致未定义/无效的行为。

回顾一下,我们保证对整个系列中的每个元素都*(result + i) = *(first + i)。我们保证,如果范围重叠,程序仍然不是未定义的。我们不保证元素的复制顺序。我们不能保证如果范围重叠,结果中存储的确切值将是什么(但我们知道它们都来自源)。

我同意Cornstalks的回答,并且+1。但是,理论必须得到实践的支持。

快速浏览一下GCC(libstdc++-v3)和Clang(libc++)的实现,就会发现它们的copy_ncopy相同(或委托给),在将对象移动到更高的地址时不支持重叠。

因此,MSVC赢得了这一轮,至少在POD的情况下,该案例委托memmove

相关内容

  • 没有找到相关文章

最新更新