下面代码中的std::move()
在Visual Studio 2013(使用Debug配置)中编译时发出运行时警告,因为它检测到dest
是nullptr
。但是,源范围为空,因此永远不应访问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);
}
答案 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。