Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

should std::copy() or std::move() of empty range require valid destination?

The std::move() in the code below issues a runtime warning when compiled in Visual Studio 2013 (with Debug configuration) because it detects that dest is a nullptr. However, the source range is empty, so dest should never be accessed. The C++ standard may be unclear as to whether this should be allowed? It states: Requires: result shall not be in the range [first,last). A nullptr would seem to satisfy that requirement.

#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);
}
like image 639
Hugues Avatar asked Oct 20 '13 17:10

Hugues


1 Answers

Not only does the Requires: clause need to be satisfied, but everything in the Effects: and Returns: clause needs to be satisfied as well. Let's go through them:

Effects: Copies elements in the range [first,last) into the range [result,result + (last - first)) starting from first and proceeding to last.

As first == last, then the range [result, result + 0) must be a valid range.

[iterator.requirements.general]/p7 states:

A range [i,i) is an empty range; ... Range [i,j) is valid if and only if j is reachable from i.

And p6 of the same section states:

An iterator j is called reachable from an iterator i if and only if there is a finite sequence of applications of the expression ++i that makes i == j.

From these paragraphs I conclude that given:

int* dest = nullptr;

Then [dest, dest) forms a valid empty range. So the first sentence in the Effects: paragraph looks ok to me:

For each non-negative integer n < (last - first), performs *(result + n) = *(first + n).

There are no non-negative integers n < 0, and so no assignments can be performed. So the second sentence does not prohibit dest == nullptr.

Returns: result + (last - first).

[expr.add]/p8 specifically allows one to add 0 to any pointer value and the result compares equal to the original pointer value. Therefore dest + 0 is a valid expression equal to nullptr. No problems with the Returns: clause.

Requires: result shall not be in the range [first,last).

I see no reasonable way to interpret that dest would be "in" an empty range.

Complexity: Exactly last - first assignments.

This confirms that no assignments can be done.

I can find no statement in the standard that makes this example anything but well-formed.

like image 110
Howard Hinnant Avatar answered Oct 03 '22 12:10

Howard Hinnant