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* ...

+ Reply to Thread
Page 1 of 4 1 2 3 ... LastLast
Results 1 to 10 of 36

std::copy implementation standard conforming?

  1. Default 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! ]


  2. Default 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! ]


  3. Default 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! ]


  4. Default 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! ]


  5. Default 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! ]


  6. Default 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! ]


  7. Default 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! ]


  8. Default 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! ]


  9. Default 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! ]


  10. Default 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! ]


+ Reply to Thread
Page 1 of 4 1 2 3 ... LastLast

Similar Threads

  1. shared_ptr implementation in the upcoming C++ standard
    By Application Development in forum c++
    Replies: 4
    Last Post: 08-22-2007, 07:45 AM
  2. GCC: non-conforming implementation of C++
    By Application Development in forum c++
    Replies: 12
    Last Post: 07-31-2007, 02:40 AM
  3. Is this standard conforming?
    By Application Development in forum Fortran
    Replies: 1
    Last Post: 07-05-2007, 02:46 AM
  4. C++ standard and current implementation
    By Application Development in forum c++
    Replies: 7
    Last Post: 06-11-2007, 11:18 AM
  5. Replies: 1
    Last Post: 07-19-2004, 09:50 PM