std::copy\n是否适用于重叠范围? 我在C++标准中查看N348 525.3.1 [Alg.Reopy],定义了4种算法: 复制 向后复制 如果 copy\n
在std::copy\n是否适用于重叠范围? 我在C++标准中查看N348 525.3.1 [Alg.Reopy],定义了4种算法: 复制 向后复制 如果 copy\n,c++,algorithm,stl,stl-algorithm,C++,Algorithm,Stl,Stl Algorithm,在复制的说明中,有以下注释25.3.1[alg.复制]/3: 要求:结果不应在[第一,最后]范围内 也就是说,当范围重叠时,copy并不总是正常工作(类似于memcpy) copy_backward和copy_if具有禁止重叠范围的类似语言(分别为25.3.1[alg.copy]/14和25.3.1[alg.copy]/8) 但是,没有禁止copy\n,也没有copy\n\u backward。这是否意味着copy\n在范围重叠时做正确的事情 (MSVC++的copy\n实现似乎委托给了std:
复制的说明中,有以下注释25.3.1[alg.复制]/3:
要求:结果不应在[第一,最后]范围内
也就是说,当范围重叠时,copy
并不总是正常工作(类似于memcpy
)
copy_backward
和copy_if
具有禁止重叠范围的类似语言(分别为25.3.1[alg.copy]/14和25.3.1[alg.copy]/8)
但是,没有禁止copy\n
,也没有copy\n\u backward
。这是否意味着copy\n
在范围重叠时做正确的事情
(MSVC++的copy\n
实现似乎委托给了std::memmove
,因此我知道在MSVC++2013上它是安全的。但如果标准另有规定,我不想依赖它)它是安全的*。为什么?因为标准没有说它不安全。他们复制25.3.1中的函数有要求:对于他们需要的东西(这是在其他复制形式中说明重叠禁止的地方)
但是,copy\n
并没有说它要求范围不重叠,这意味着它可以,因为它没有明确禁止。如果它需要,它会声明它
*编辑:当我指的是“安全”时,我的意思是这样做不是未定义的行为或错误的程序。但是,如果内存范围重叠,结果不能保证是您可能想要的。我们唯一能保证的是:
对于每个非负整数i
,执行*(结果+i)=*(第一个+i)
调用具有重叠范围的函数是不被禁止的,并且不会导致未定义的行为
因此,我们可以推断,如果范围重叠,则存储在目标中的结果不再保证是精确的(按顺序)源文件的副本。我们保证目标文件中的每一个值都来自源文件,尽管这些值的精确性取决于重叠和元素的精确复制顺序
因此,如果“安全”是指目标始终具有源代码的完美副本(如memmove
),那么不,它不是“安全”的。但它是安全的,因为它本身不会导致未定义/无效的行为
总而言之,我们保证*(result+i)=*(first+i)
将对整个范围内的每个元素执行。我们保证,如果范围重叠,程序仍然没有定义。我们不保证复制元素的顺序。我们不保证如果范围重叠,结果中存储的确切值将是什么(但我们确实知道它们都来自源头)。我同意玉米秸秆的答案,而且+1。但是,理论必须得到实践的支持
快速浏览一下GCC(libstdc++-v3)和Clang(libc++)的实现,可以发现它们的copy\n
与copy
相同(或委托给copy
),在将对象移动到更高的地址时不支持重叠
因此,MSVC赢得了这一轮,至少在POD案例中,授权给memmove
当迭代器不支持随机访问时,copy\n
如何进行安全检查?(它只需要一个输入迭代器和一个输出迭代器……)@Billy cplusplus.com说,如果范围重叠,result指向的范围中的某些元素可能有未定义但有效的值。
但我不知道这有多可靠。@remyabel:cplusplus.com==非常不可靠。@BillyONeal:Updated。对不起,我最初的意思是“安全”与您可能使用的不同。因此允许传递重叠范围,但实际上这样做会产生不可预测的结果,因此在任何可能的情况下都是无用的?多么奇怪的规范。为什么不将其与其他复制
函数一样对待?它们可能在想什么?(我同意规范似乎是这么说的,所以+1。但这太奇怪了。)“MSVC++对copy\n
的实现似乎委托给了std::memmove
”请注意,我们只在这种转换正确的情况下才这样做;也就是说,迭代器是指向可复制对象的指针。@James:当然。:)在这种情况下,这恰好是一个安全的转换。@James:啊,我明白你的意思。如果输入是例如std::list
iterators,那么在MSVC++的实现中是不安全的。听起来像是对我的回答……哇,这是一个奇怪的边缘情况,我想说这可能是个错误(他们打算这样做)但它似乎几乎是故意被忽略了……原始版本确实对复制有这样的要求。我不知道为什么这不在标准中。你可以提交一个问题。顺便说一句,复制
只禁止输出从输入范围开始的重叠,但在输出范围结束时,它可以正常工作(即复制到左侧)。