应该std :: copy()或std :: move()的空范围是否需要有效的目的地?

时间:2013-10-20 17:37:45

标签: c++ visual-studio c++11

下面代码中的std::move()在Visual Studio 2013(使用Debug配置)中编译时发出运行时警告,因为它检测到destnullptr。但是,源范围为空,因此永远不应访问dest。 C ++标准可能不清楚是否允许这样做? 它声明:要求:结果不应在[first,last]范围内。 nullptr似乎满足了这一要求。

#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec;
    int* dest = nullptr;
    // The range [begin(vec),end(vec)) is empty, so dest should never be accessed.
    // However, it results in an assertion warning in VS2013.
    std::move(std::begin(vec), std::end(vec), dest);
}

3 个答案:

答案 0 :(得分:15)

不仅需要满足 Requires:子句,而且 Effects: Returns:子句中的所有内容都需要满足同样。让我们来看看:

  

效果:[first,last)开始,将[result,result + (last - first))范围内的元素复制到范围first中   继续last

作为first == last,范围[result, result + 0)必须是有效范围。

[iterator.requirements.general] / p7陈述:

  

范围[i,i)是一个空范围;当且仅当Range [i,j)可以j访问时,i才有效。

同一节的第6页说明:

  

迭代器j只能从迭代器i调用   如果表达式++i的应用程序的有限序列   这使得i == j

从这些段落中我得出结论:

int* dest = nullptr;

然后[dest, dest)形成一个有效的空范围。所以 Effects:段落中的第一句对我来说没问题:

  

对于每个非负整数n < (last - first),执行*(result + n) = *(first + n)

没有非负整数n < 0,因此无法执行任何分配。所以第二句不禁止dest == nullptr

  

返回: result + (last - first)

[expr.add] / p8特别允许将0添加到任何指针值,并且结果比较等于原始指针值。因此dest + 0是一个等于nullptr的有效表达式。 返回:子句没有问题。

  

要求: result不得在[first,last)范围内。

我认为没有合理的方法可以解释dest在“空白范围内”。

  

复杂性:完全last - first作业。

这证实无法完成任务。

我在标准中找不到任何声明,使得这个例子不是格式良好。

答案 1 :(得分:-1)

Visual Studio中STL的调试版本执行其他参数验证。在这种情况下,它验证dest不是null,因为它不应该是,这是失败的。发布版本可能会按预期运行,从不使用dest但不会使输入数据有效。

STL的调试版本试图通过说“你的输入不好”来帮助你。虽然在某些情况下输入错误可能不是问题,但验证器无法知道在什么条件下传递错误数据。就个人而言,我宁愿让VS告诉我调试版本中输入错误,而不是在生产中抛出运行时异常。

当然,你可能会这样做:

int* dest = nullptr;
if (vec.size() > 0) dest = realDest;
std::move(std::begin(vec), std::end(vec), dest);

但是验证器并不知道所以它假定最坏,特别是因为修复它对你来说非常容易(只是总是传入一个有效的输出迭代器)并且没有警告你它可能会对你的应用程序产生可怕的后果。生产中的运行时间。

答案 2 :(得分:-1)

这个答案来自@Philipp Lenk的评论。如果他提供答案并且你觉得它是可以接受的,那就选择他超过我的答案,并请他投票给他原来的评论。

  

§25.1.5:在整个条款中,模板参数的名称是   用于表示类型要求[...]如果算法的模板   参数是OutputIterator,OutputIterator1或OutputIterator2 ,.   实际模板参数应满足输出的要求   迭代器。

     

§24.2.4:类或指针类型X满足a的要求   如果X满足Iterator要求,则输出迭代器   表108中的表达式是有效的并具有指示的语义。   表格的第一行:*r = o,注释为post: r is incrementable.

int* dest = nullptr;
*dest = 5;
++dest;

以上代码无效。在这种情况下,您无法分配给*dest,因此根据标准,您无法为dest传递nullptr。