std::copy implementation standard conforming? - c++
This is a discussion on std::copy implementation standard conforming? - c++ ; Hi All,
We came across a crash after upgrading out compiler to Visual Studio
2005 SP1. I traced this down to the checked iterator support. The
function looks a little like this:
template<class InIt, class OutType, size_t Size>
inline
OutType* ...
-
std::copy implementation standard conforming?
Hi All,
We came across a crash after upgrading out compiler to Visual Studio
2005 SP1. I traced this down to the checked iterator support. The
function looks a little like this:
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];
}
DataStore* data = (DataStore*)malloc(array.length() + sizeof(unsigned
int));
std::copy(array.begin(), array.end(), data->data);
Although I know this part is non-conforming, this code has been
working ok for many years, and is of the style allowed by C99 I
understand.
Now the array binds to the new copy version, and the check_iterator
gives an error during the copy as it thinks the array is only one byte
long.
The question is, is this std::copy overload allowed by the standard?
Thanks for your help!
Cheers,
Ben
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: std::copy implementation standard conforming?
On Jun 19, 5:57 pm, Ben <gro...@theyoungfamily.co.uk> wrote:
> Now the array binds to the new copy version, and the check_iterator
> gives an error during the copy as it thinks the array is only one byte
> long.
It's not that it thinks it is one byte long. It is one byte long.
Accessing an array past the end is undefined behaviour.
> The question is, is this std::copy overload allowed by the standard?
Yes.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: std::copy implementation standard conforming?
In article <1182276861.155331.76080@q75g2000hsh.googlegroups.com>,
Mathias Gaunard <loufoque> wrote:
> On Jun 19, 5:57 pm, Ben <gro...@theyoungfamily.co.uk> wrote:
>
> > Now the array binds to the new copy version, and the check_iterator
> > gives an error during the copy as it thinks the array is only one byte
> > long.
>
> It's not that it thinks it is one byte long. It is one byte long.
> Accessing an array past the end is undefined behaviour.
>
>
> > The question is, is this std::copy overload allowed by the standard?
>
> Yes.
The problem is not undefined behavior but the fact that template
parameter deduction does not do conversions that is
void bar(T[1] x);//1
void bar(T *x);//2
template <class T> foo(T x) {bar (x);}
char x[1];
char *y = x;
foo(x) ;// calls bar(char[1]);
foo(y) ;// calls bar(char *);
data->data is a a one byte array not a byte *. Cast is the solution
or a named temp like
byte *out = data->data; // this does the conversion.
std::copy(array.begin(),array.end(),out);
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: std::copy implementation standard conforming?
> The problem is not undefined behavior but the fact that template
> parameter deduction does not do conversions that is
>
> void bar(T[1] x);//1
> void bar(T *x);//2
> template <class T> foo(T x) {bar (x);}
>
> char x[1];
> char *y = x;
>
> foo(x) ;// calls bar(char[1]);
> foo(y) ;// calls bar(char *);
>
> data->data is a a one byte array not a byte *. Cast is the solution
> or a named temp like
> byte *out = data->data; // this does the conversion.
> std::copy(array.begin(),array.end(),out);
Implementation of std::copy is standard conforming. When you have UB
in your program, compiler can do whatever he wants. Usually the best
it can do is to signal you somehow (assert, runtime error etc).
Previous implementation did nothing to detect UB while new
implementation of std::copy detects UB and signals about it.
Roman Perepelitsa
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: std::copy implementation standard conforming?
On Jun 19, 10:38 pm, Mathias Gaunard <loufo...> wrote:
> On Jun 19, 5:57 pm, Ben <gro...@theyoungfamily.co.uk> wrote:
>
> > Now the array binds to the new copy version, and the check_iterator
> > gives an error during the copy as it thinks the array is only one byte
> > long.
>
> It's not that it thinks it is one byte long. It is one byte long.
> Accessing an array past the end is undefined behaviour.
>
I understand that, but it is fairly standard practise.
> > The question is, is this std::copy overload allowed by the standard?
>
> Yes.
>
But std::copys third argument should be an output iterator, and an
array reference is not an output iterator.
Cheers,
Ben
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: std::copy implementation standard conforming?
Carl Barron wrote:
>
> The problem is not undefined behavior but the fact that template
> parameter deduction does not do conversions that is
>
> void bar(T[1] x);//1
> void bar(T *x);//2
> template <class T> foo(T x) {bar (x);}
I assume you meant
template <class T> foo(T& x) {bar (x)
Otherwise, T can never be deduced as being an array.
>
> char x[1];
> char *y = x;
>
> foo(x) ;// calls bar(char[1]);
> foo(y) ;// calls bar(char *);
>
> data->data is a a one byte array not a byte *. Cast is the solution
> or a named temp like
> byte *out = data->data; // this does the conversion.
> std::copy(array.begin(),array.end(),out);
Or without the extra variable:
std::copy(array.begin(),array.end(),&data->data[0]);
Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://www.eskimo.com/~scs/C-faq/top.html
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: std::copy implementation standard conforming?
In article <1260921.WR1b86AXkF@ingen.ddns.info>, Bart van Ingen Schenau
<bart@ingen.ddns.info> wrote:
> Carl Barron wrote:
>
> >
> > The problem is not undefined behavior but the fact that template
> > parameter deduction does not do conversions that is
> >
> > void bar(T[1] x);//1
> > void bar(T *x);//2
> > template <class T> foo(T x) {bar (x);}
>
> I assume you meant
> template <class T> foo(T& x) {bar (x)
> Otherwise, T can never be deduced as being an array.
>
no T the type is the type of the argument [no conversions] if T is
char [1] there is no conversion to char * and the type used is char
[1]. If T is a char * then there still is no conversion. With a non
templated function baz(char *) a char[1] is converted to a char *,
but not with foo above.
Does this make any sense yet? It is a common 'gotcha' for the unwary.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: std::copy implementation standard conforming?
Carl Barron wrote:
> In article <1260921.WR1b86AXkF@ingen.ddns.info>, Bart van Ingen
> Schenau <bart@ingen.ddns.info> wrote:
>
>> Carl Barron wrote:
>>
>> >
>> > The problem is not undefined behavior but the fact that template
>> > parameter deduction does not do conversions that is
>> >
>> > void bar(T[1] x);//1
>> > void bar(T *x);//2
>> > template <class T> foo(T x) {bar (x);}
>>
>> I assume you meant
>> template <class T> foo(T& x) {bar (x)
>> Otherwise, T can never be deduced as being an array.
>>
> no T the type is the type of the argument [no conversions] if T is
> char [1] there is no conversion to char * and the type used is char
> [1]. If T is a char * then there still is no conversion. With a non
> templated function baz(char *) a char[1] is converted to a char *,
> but not with foo above.
> Does this make any sense yet? It is a common 'gotcha' for the
> unwary.
No, it does not make any sense.
According to my understanding of 14.8.2.1 (C++ standard), the T in the
following snippet must be deduced as 'char *', not as 'char[1]'.
template <class T> void f(T x) {};
char c[1];
f(c);
Note particularly 14.8.2.1/2, first bullet. P is not a reference type
(because f() does not accept a reference parameter) an A is an array
type (typeof c == char[1]). Therefor, the array-to-pointer conversion
is applied *before* type deduction. Thus, P is deduces as 'char *'.
With reference parameters, your reasoning would have been correct. The T
would have been deduces as an array type.
Bart v INgen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://www.eskimo.com/~scs/C-faq/top.html
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: std::copy implementation standard conforming?
Roman.Perepelitsa wrote:
>> The problem is not undefined behavior but the fact that template
>> parameter deduction does not do conversions that is
>>
>> void bar(T[1] x);//1
>> void bar(T *x);//2
>> template <class T> foo(T x) {bar (x);}
>>
>> char x[1];
>> char *y = x;
>>
>> foo(x) ;// calls bar(char[1]);
>> foo(y) ;// calls bar(char *);
>>
>> data->data is a a one byte array not a byte *. Cast is the solution
>> or a named temp like
>> byte *out = data->data; // this does the conversion.
>> std::copy(array.begin(),array.end(),out);
>
> Implementation of std::copy is standard conforming. When you have UB
> in your program, compiler can do whatever he wants. Usually the best
> it can do is to signal you somehow (assert, runtime error etc).
> Previous implementation did nothing to detect UB while new
> implementation of std::copy detects UB and signals about it.
I don't have a copy of the standard on me, but to the best of my
knowledge (and memory), as long as the struct is a POD and extra memory
was allocated properly for it, the struct hack is 100% legal in C++ and
has defined behavior.
Andrei
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: std::copy implementation standard conforming?
In article <2627625.jTjtEFmNbQ@ingen.ddns.info>, Bart van Ingen Schenau
<bart@ingen.ddns.info> wrote:
> Note particularly 14.8.2.1/2, first bullet. P is not a reference type
> (because f() does not accept a reference parameter) an A is an array
> type (typeof c == char[1]). Therefor, the array-to-pointer conversion
> is applied *before* type deduction. Thus, P is deduces as 'char *'.
>
> With reference parameters, your reasoning would have been correct. The T
> would have been deduces as an array type.
>
that is what the standard says, I stand corrected and informed my
examples are too simple
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.
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.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Similar Threads
-
By Application Development in forum c++
Replies: 4
Last Post: 08-22-2007, 07:45 AM
-
By Application Development in forum c++
Replies: 12
Last Post: 07-31-2007, 02:40 AM
-
By Application Development in forum Fortran
Replies: 1
Last Post: 07-05-2007, 02:46 AM
-
By Application Development in forum c++
Replies: 7
Last Post: 06-11-2007, 11:18 AM
-
By Application Development in forum Compilers
Replies: 1
Last Post: 07-19-2004, 09:50 PM