Re: std::copy implementation standard conforming?
On 6/22/07 8:53 AM, in article 220620070342221557%cbarron413@adelphia.net,
"Carl Barron" <cbarron413@adelphia.net> wrote:
The original post states:
template<class InIt, class OutType, size_t Size>
inline
OutType* copy(InIt First, _InIt Last, OutType (&Dest)[Size])
{
return copy(First, Last, make_checked_array_iterator(_Dest, _Size));
}
We're using it to copy into a struct that has an overallocated array
e.g
struct DataStore
{
unsigned int length;
byte data[1];
}
std::copy(array.begin(), array.end(), data->data);
The illegal overload is the one chosen and it if the apparent typos
are ignored and make_checked_array_iterator creates an iterator that
throws an exception attemping to store data outside of the range
[Dest, Dest+Size) , then it will be chosen and only the first byte
copied.
An implementation may add its own overloads to Standard Library functions-
just as long as: "a call to a global or non-member function signature [...]
behaves the same as if the implementation declares no additional global or
non-member function signatures." [?17.4.4.3] In other words, the existence
of an implementation-defined overload of a Standard Library function is OK,
just as long as its existence has no affect on the behavior of user code.
In this case, the Microsoft C++ compiler has created an optional, "checked"
version of std::copy() that cleverly overloads the original routine so that
it will be invoked whenever std::copy()'s third parameter (the destination
of the copied items) is the name of an array. So the checked version of
std::copy() is therefore able to verify the the items being copied remain
within the declared bounds of the destination array. Because as long as the
user program does not overrun the bounds of the destination array, the
program's behavior remains defined; and the existence of the checked
std::copy() has no discernable effect on the program's well-defined
behavior.
On the other hand, if the program's call to std::copy() does copy objects
beyond the bounds of the destination array, then all bets are off. The
program's behavior becomes at that point, undefined. Therefore the
implementation has no obligation to adhere to its previous behavior (and in
fact it does not - instead it helpfully crashes as designed).
The code is 'illegal' because it is forbidden to overload templates in
namespace std. But if forced to use this 'illegal' code then the
workaround is to cast to a byte *, or create a temp byte * and use it.
This will remove the 'illegal' overload from consideration.
The entire reason for enabling "checked" routines in the first place - is to
find bugs (especially those that cause undefined behavior) in a C++ program.
Therefore, it makes little sense that once a checked routine does expose a
bug in the user program, to write code to bypass the checked routine - as if
concealing the bug somehow fixes it. (Moreover, checked routines are usually
enabled only in debugging builds anyway).
So the only sensible thing to do, in this situation (or any other situation
in which a program's undefined behavior has been made evident) - is not to
conceal or dispute the existence of the error - but to fix it.
Greg
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]