std复制问题

时间:2010-02-10 23:28:42

标签: c++

使用std :: copy复制数组时有没有办法检查副本是否正确完成?特别是如果你在unsigned char数组中有十六进制值。我不确定如何验证副本是否通过,即使它确实正确复制了一个数组中的值。

2 个答案:

答案 0 :(得分:3)

实际上,复制失败的唯一方法是复制到类似back_insert_iterator的内容,在这种情况下,目标容器中的分配可能会失败。通常会抛出异常 1

1 对于那些想要血腥细节的人来说,在这种情况下,“通常”意味着你没有提供自己的分配器,除了在失败的情况下抛出异常之外还有其他事情。

编辑:也许我应该更明确一点:我说的是你有机会发现的失败。 std::copy的前提条件是目标迭代器不能在源范围内。违反这会导致未定义的行为。同样,如果您执行的任务(直接或通过复制或转换等算法)超出目标类型的范围,您(再次)将获得未定义的行为。

未定义行为的定义是标准对实现放置 no 要求。换句话说,如果你这样做,任何都可能发生。根本无法保证程序的行为。没有明智的方式来讨论如何发现这样的事情,因为语言说如果你的程序做了这样的事情,你就不能依赖任何事情

再次编辑:因为似乎对未定义的行为存在一些误解。为了做任何好事,如果你担心可能导致未定义行为的事情,你需要阻止它们发生,而不是试图复制然后试图弄清楚它是否成功。到那时为时已晚;如果程序执行了未定义的操作,全部程序的行为未定义。

因此,要处理目标迭代器在源迭代器范围内的可能性,或者源数据在目标数据类型范围之外的情况,您需要检查前面的那些,并且从不甚至尝试未定义的行为。

template <class T, class U>
safe_copy(T source_start, T source_end, U dest) { 
    if (std::less(source_start, dest) && std::less(dest, source_end))
        throw(std::range_error("Output iterator within input range");
    std::transform(source_start, source_end, dest, checked_convert);
}

目前,我还没有尝试定义checked_convert。它可能会进行饱和转换,或者如果值超出范围等则抛出异常, - 完全取决于所涉及的数据类型。但是,无论如何,它确保在分配到目的地之前,源值适合目标范围

答案 1 :(得分:0)

您可以使用以下方法仔细检查副本是否成功:( assert来自<cassert>

assert ( std::equal( src_first, src_last, dst ) );

这将捕获src_first < dst < src_last导致的问题。但更好的方法是直接断言该条件:(这需要随机访问迭代器,即来自vectordeque,并且它们必须属于同一个容器 - 通常是如果你担心重叠,可以使用

assert ( src_last < dst || dst <= src_first );

但您似乎关注其他类型的问题,例如类型兼容性。没有灵丹妙药,但只要可以测试源和目标类型是否相等,上面的第一个建议将保证您的安全。

旁边:hex只是base-16数字系统,因此如果用base-16编写,任何数据都是“十六进制值”。

编辑:我有几个downvotes因为assert不适合生产代码,并且因为类型转换被认为是不安全的,因为某些情况不是由C ++标准定义的。

首先,如果您不想assert,请删除assert并将条件用于其他内容!不是火箭科学。

其次,您有责任确保不会因数字异常而崩溃。首先,整数强制转换中没有异常也没有未定义的行为。因此,std::equal的上述用法保证适用于任何本机整数类型和值,句点。也不是火箭科学。

如果您使用的是浮点类型,那么当您使用float或其他方式将int转换为std::copy时,C ++可能会导致崩溃和刻录:将float-to-int溢出的行为保留为undefined。这是否意味着在没有首先检查不会发生溢出的情况下,你不能将浮点数转换为int?当然不是! C ++没有定义行为,但IEEE 754确实如此。此外,IEEE 754定义所有 所有您可以执行的操作的行为(尽管未定义),并且它已经无处不在了。 20年。

IEEE 754进一步建议默认操作环境不会引发任何数字异常,POSIX保证这一点。这意味着你可以对任何浮点数做任何事情而不用担心崩溃! (只要您在POSIX或类似的数字系统中,并且没有专门启用异常。)

崩溃和“未定义的行为”之外,之后测试平等在数字上是一个可靠的操作。根据标准的§5¶7,C ++通过将“较小”类型的操作数转换(提升)为“更大”类型的操作数来比较本机类型的数字。只有当两个值都可以用更大范围的类型表示时,平等才会成立,并且它们在该类型中的数字相同。

非数字的值可能会失败。如果您复制其中包含NaN的向量,std::equal调用将返回false,因为NaN不能等于任何其他内容,甚至不是相同的NaN,因为{{1}代表Not a Number,而不是它所做的事情。

因此,我的免责声明“不是银弹......只要源和目的地类型可以进行相等的测试,就是安全的。”你需要一般都知道自己在做什么。推动浮点的界限往往会引起头痛。做你的作业。

但是崩溃不会发生,未定义的行为不会产生这种情况,尽管标准对未定义行为的免责声明,因为行为 IS 在其他地方定义,无论是在IEEE 754中还是在(不太可能)FPU中手册,如果不符合要求。

编辑2:另一个答案中提到的NaN功能只是围绕一个众所周知的实用程序checked_convert跳舞。如果您想安全地转换数字并获取有关 操作失败的具体信息,如果确实如此,那就是您想要的工具。不要试图编写自己的代码,这很棘手。