2

I have this code:

#include <set>

int main() {
    int array[] = { 0 };
    std::set<int> stdset(&array[1], &array[1]);
}

which obtains address of element right beyond last array element and converts it into iterator. Basically the same as what std::vector::end() does.

It's legal to do this:

 std::vector<int> vec;
 std::set<int> stdset(vec.end(), vec.end());

because the "last" iterator is a non-inclusive limit.

Is it legal to do the same with raw array as in the first code snippet?

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 1
    The standard container range constructors are templates, no conversion is involved. – user657267 Jul 21 '16 at 08:44
  • Aside: `&array[0] + 1` is legal. So is the even simpler `array + 1`. –  Jul 21 '16 at 09:10
  • 2
    This is a good question. I'm *not at all* sure whether `&array[n]` is legal (as opposed to `array + n` or `&array[0] + n`, which are legal). It's independent from iterators I think: The question is solely whether the expression `&array[n]` is legal. -> And here's the Q+A: http://stackoverflow.com/questions/988158/take-the-address-of-a-one-past-the-end-array-element-via-subscript-legal-by-the – Martin Ba Jul 21 '16 at 09:32
  • Fir the record, you cannot convert a pointer to an iterator at all, so the answer to the *title* question is an obvious "no". – n. m. could be an AI Jul 21 '16 at 09:33

4 Answers4

1

You can take the address of one-past-the-end of any array in C++.

You cannot dereferrence and use the result, but you can compare it to other pointers to the same array and to other one-past-the-end of same array.

What you are doing in the OP is defined behaviour, and represents an empty range.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1

There is no conversion involved. Pointers support the same operations as random-access iterators (unary * operator, ++ and + operators, etc.) and therefore can be used as iterators. Standard-library functions which take iterators are templated on the type of the iterator, so they will take a pointer without converting it to anything.

This, along with the fact that a pointer to one past the end of an array is valid (as long as you don't dereference it), means that your code is correct.

interjay
  • 107,303
  • 21
  • 270
  • 254
1

You're not converting anything: pointers are valid iterators over vectors.

Getting a pointer to the element just past the end of an array is legal, but it's not legal to dereference such pointer.

ANSI C, § 5.7 paragraph 5:

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

I did not find a reference to this within a C++ standard quote online, and I don't own a copy of the C++ standard, so I can't prove it's still up to date regarding C++, but it probably is.

TL;DR: Your code is legal.

-1

To be honest, I do not know the answer to your question according to any specs. Nevertheless, the problem I see with your approach is that you are tying your implementation to implementation details in the library you are using.

If you tie your implementation to the interfaces exposed by the libraries you use, it is less likely that your consuming code will be broken should the implementation of those libraries change. That might not be very relevant in this particular case, because the memory layout of an array is not likely to change in the near future, but if it did, the runtime library developer might also change the implementation of the iterating functions accordingly, so if you use the exposed functions, your code should keep on working as expected. However if your code depends on implementation details of the libraries, it might be you who will have to go through all your case uses and change them accordingly.

EDIT:

I am sorry, I do not think I expressed myself very clearly; I am not talking about your code but about your approach. One of the benefits of encapsulation is that it allows writing code components that are excellent performers each of their own task, and then applications by combining the functionality provided by multiple code components. Having multiple levels of abstraction enables us to design the upper levels without worrying about the tiny details in the lower levels.

If the different components that make up the whole application are kept isolated from each other's implementation details, components may be upgraded easily without breaking compatibility, as long as the components keep their minimum interface and their implementation behaves correctly. If the different components are made interdependent of each other's implementation, then upgrades become much more difficult because changes need to be made respecting the internal structures of the components involved; a seemingly innocuous modification in a lower level component (like inserting a new member variable between two older ones) can have totally unforeseen consequences in a completely unrelated piece of code "cleverly" relying on the component's internal structure.

In the art of programming, you can use whichever resources you find in order to transform your inputs into your outputs, but that does not mean that all posibilities carry the same implications. If you are worried about execution time and the overhead of calling a function is unacceptable, then you might gain some extra cycles by skipping an object-oriented approach altogether and iterate your array by index. If the execution time is not so critical that it allows for a call to a public method on an interface, then by using it you would gain smaller upgrade nightmares.

Carvo Loco
  • 2,068
  • 13
  • 21
  • I don't know what libraries or implementation details you are referring to, but the memory layout of an array is specified in the standard and cannot be changed. – interjay Jul 21 '16 at 08:59
  • Thanks for your feedback, interjay. I've expanded my answer in case you find it interesting. Have a good day! – Carvo Loco Jul 21 '16 at 10:19