Topic: memcpy to POD with const member


Author: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: Wed, 30 May 2001 21:05:12 GMT
Raw View
glancaster <glancaster@ntlworld.com> wrote in message
news:s32R6.16522$lm5.2154492@news6-win.server.ntlworld.com...
> Andrei Iltchenko:
> > A POD-struct can contain a const member sub-object, so can a
> > POD-union. It's just that in that case, when defining an object of
> > such a type you have to use a brace-enclosed initializer list and
> > provide an initializer for the const member sub-object.
> >
> > It follows that:
> > 1. You cannot create objects of such types using a new-expression;
> > 2. In the case of a POD-union if the const member sub-object is not
> > the first member of the union, there's no well-formed way of creating
> > an object of this union type.
> >
> > The fact that POD class types can have const member sub-object has a
> > reflection in the Standard -- read 5.3.4/15 bullet 1, sub-bullet 2.
>
> Weird. This really only mentions const members in passing, but it is the
> only part of the standard I have found that talks about allowing or
> disallowing const sub-objects of POD-structs at all!
>
> I assumed there was a prohibition *somewhere* since both my compilers
> (MSVC++6 and Borland C++ Builder 5) don't accept structs with const
members
> and no ctor, even if I initialise them with an initializer list.

It's not surprising as each of them (especially MSVC) implements the
language that only look like C++, which nontheless might come handy.


> So, I'm still confused. If it is as you say it is then both compilers are
> wrong as is paragraph 3.9/3 of the standard.

They are both wrong indeed.

If you want to check the well-formdness of a given C++ construct, you'd be
better off using a compiler based on the EDG C++ front-end (Comeau C++ for
instance) or the latest snapshot of gcc 3.0 (the official release is due to
come out soon).

Both the front-ends have on-line versions:
http://www.comeaucomputing.com/tryitout/
http://www.codesourcery.com/gcc-compile.shtml

Both the compilers translate the sample program below without any errors:

const union  {
   const double   m_datum1;
   int   m_datum2;
}  gc_union = {   3.,   };

const struct  {
   const double   m_datum1;
   const int   m_datum2;
}  gc_struct = {   3.,  2,   };

int  main()
{   return  0;   }


Cheers,

Andrei Iltchenko.



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "glancaster" <glancaster@ntlworld.com>
Date: Thu, 31 May 2001 19:33:12 GMT
Raw View
Andrei Iltchenko:
> If you want to check the well-formdness of a given C++ construct, you'd be
> better off using a compiler based on the EDG C++ front-end (Comeau C++ for
> instance) or the latest snapshot of gcc 3.0 (the official release is due
to
> come out soon).

I prefer to look at the standard if I'm not sure of a C++ construct. In this
case though I can't see anything that helps me, so I'm having to fall back
on trusting the compilers.

> Both the front-ends have on-line versions:
> http://www.comeaucomputing.com/tryitout/
> http://www.codesourcery.com/gcc-compile.shtml

Yes, these are both excellent compilers from a standards-conformance point
of view, but even so neither of them is 100% standard compliant (whatever
that means) yet.

> Both the compilers translate the sample program below without any errors:
>
> const union  {
>    const double   m_datum1;
>    int   m_datum2;
> }  gc_union = {   3.,   };
>
> const struct  {
>    const double   m_datum1;
>    const int   m_datum2;
> }  gc_struct = {   3.,  2,   };
>
> int  main()
> {   return  0;   }

GCC compiles with no errors or warnings. Comeau issues some warnings, the
only one relevant to our discussion being:

"246.c", line 6: warning: class "<unnamed>" defines no constructor to
          initialize the following:
            const member "<unnamed>::m_datum1"
            const member "<unnamed>::m_datum2"
  const struct  {

I have mailed Comeau support to ask why this is a warning.

To get back to my original question, I reformulate it so:

#include <cstring>

struct test
{
   const int a;
};

int main()
{
    test s = { 1 };
    test d = { 2 };
    std::memcpy( &d, &s, sizeof( test ) );
}

I assume you consider test to be a valid POD-struct. Please correct me if I
am wrong.

Do you consider that the memcpy line is valid according to 3.9/3 of the
standard? If yes, do you think that this is a mistake in the standard?

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: Thu, 31 May 2001 22:00:04 GMT
Raw View
glancaster <glancaster@ntlworld.com> wrote in message
news:HmoR6.890$HL5.84801@news6-win.server.ntlworld.com...
> Andrei Iltchenko:
> > If you want to check the well-formdness of a given C++ construct, you'd
be
> > better off using a compiler based on the EDG C++ front-end (Comeau C++
for
> > instance) or the latest snapshot of gcc 3.0 (the official release is due
> to
> > come out soon).
>
> I prefer to look at the standard if I'm not sure of a C++ construct.

Yeah, that's the right way of approaching this.


> In this case though I can't see anything that helps me,

That's strange. In my opinion the Standard is absolutely clear about
allowing POD class types to have const non-static data members. To
understand which type is a POD-struct or POD-union you need to read 8.5.1/1,
which explains what an aggregate is, and then 9/4, which adds to the
requirements stated in 8.5.1/1. Among the restrictions explained there
there're none that restrain a POD class type from having a const non-static
data member. Besides, there are sentences in the Standard that explicitly
mention POD class types as directly containing const-qualified data
members -- read 5.3.4/15 bullet 1, sub-bullet 2 and 12.6.2/4 bullet 2.


> > Both the front-ends have on-line versions:
> > http://www.comeaucomputing.com/tryitout/
> > http://www.codesourcery.com/gcc-compile.shtml
>
> Yes, these are both excellent compilers from a standards-conformance point
> of view, but even so neither of them is 100% standard compliant (whatever
> that means) yet.

Agree.


> > Both the compilers translate the sample program below without any
errors:
> >
> > const union  {
> >    const double   m_datum1;
> >    int   m_datum2;
> > }  gc_union = {   3.,   };
> >
> > const struct  {
> >    const double   m_datum1;
> >    const int   m_datum2;
> > }  gc_struct = {   3.,  2,   };
> >
> > int  main()
> > {   return  0;   }
>
> GCC compiles with no errors or warnings. Comeau issues some warnings, the
> only one relevant to our discussion being:
>
> "246.c", line 6: warning: class "<unnamed>" defines no constructor to
>           initialize the following:
>             const member "<unnamed>::m_datum1"
>             const member "<unnamed>::m_datum2"
>   const struct  {
>
> I have mailed Comeau support to ask why this is a warning.

I see nothing unusual here, as the implementation simply issued a diagnostic
without rejecting the well-formed program featuring no undefined behavior,
the diagnostic being the right one as <unnamed> defines no constructor
indeed. It could also issue a warning saying, for example, that gc_struct is
defined in namespace scope, which would also be perfectly OK as long as a
well-formed program without undefined behavior was not rejected. Anyway,
you'd better mail your question to EDG as the warnings that you see have
little to do with the work being done by Comeau, as the Comeau on-line
compiler only shows the diagnostics issued while the source file is being
compiled, and any compiler based on the same version of the C++ front-end
from Edison Design Group will issue the same diagnostics.


> To get back to my original question, I reformulate it so:
>
> #include <cstring>
>
> struct test
> {
>    const int a;
> };
>
> int main()
> {
>     test s = { 1 };
>     test d = { 2 };
>     std::memcpy( &d, &s, sizeof( test ) );
> }
>
> I assume you consider test to be a valid POD-struct. Please correct me
> if I am wrong.
>
> Do you consider that the memcpy line is valid according to 3.9/3 of the
> standard?

No, it's not. The memcpy line is an example of undefined behavior.

I believe this to be a very interesting observation, as 3.9/3 allows what is
forbidden by 7.1.5.1/4 if the value of an object of a POD class type
containig a const non-static data member is copied into another object of
the same type with 'memcpy'. This is not the only problem that arises with
PODs and the guarantees given in 3.9/2-3, see issue 273 at:
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html

I would encourage you to submit a Defect Report.


Regards,

Andrei Iltchenko.



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "glancaster" <glancaster@ntlworld.com>
Date: Sat, 2 Jun 2001 02:25:20 GMT
Raw View
Garry Lancaster:
> > I prefer to look at the standard if I'm not sure of a C++ construct.

Andrei Iltchenko:
> Yeah, that's the right way of approaching this.

> > In this case though I can't see anything that helps me,
>
> That's strange. In my opinion the Standard is absolutely clear about
> allowing POD class types to have const non-static data members. To
> understand which type is a POD-struct or POD-union you need to read
8.5.1/1,
> which explains what an aggregate is, and then 9/4, which adds to the
> requirements stated in 8.5.1/1. Among the restrictions explained there
> there're none that restrain a POD class type from having a const
non-static
> data member.

I've read all these sections and like you, didn't notice anything about
const non-static data members. I guess I was looking for something explicit
to say this *is* allowed. Perhaps that was a bit naive, but as I already
indicated my compilers colluded to confuse me ;-)

> Besides, there are sentences in the Standard that explicitly
> mention POD class types as directly containing const-qualified data
> members -- read 5.3.4/15 bullet 1, sub-bullet 2 and 12.6.2/4 bullet 2.

I hadn't noticed these until you pointed them out.

[snip]

> > GCC compiles with no errors or warnings. Comeau issues some warnings,
the
> > only one relevant to our discussion being:
> >
> > "246.c", line 6: warning: class "<unnamed>" defines no constructor to
> >           initialize the following:
> >             const member "<unnamed>::m_datum1"
> >             const member "<unnamed>::m_datum2"
> >   const struct  {
> >
> > I have mailed Comeau support to ask why this is a warning.
>
> I see nothing unusual here, as the implementation simply issued a
diagnostic
> without rejecting the well-formed program featuring no undefined behavior,
> the diagnostic being the right one as <unnamed> defines no constructor
> indeed. It could also issue a warning saying, for example, that gc_struct
is
> defined in namespace scope, which would also be perfectly OK as long as a
> well-formed program without undefined behavior was not rejected. Anyway,
> you'd better mail your question to EDG as the warnings that you see have
> little to do with the work being done by Comeau, as the Comeau on-line
> compiler only shows the diagnostics issued while the source file is being
> compiled, and any compiler based on the same version of the C++ front-end
> from Edison Design Group will issue the same diagnostics.

Actually, Comeau were very helpful - Comeau C++ is *their* product,
regardless of how they sub-contract various parts of the implementation
work, so they seem happy to answer any query on it.

And you are right, they said their warning isn't intended to indicate a
violation of the standard - I believe they would use an error for that.

> > To get back to my original question, I reformulate it so:
> >
> > #include <cstring>
> >
> > struct test
> > {
> >    const int a;
> > };
> >
> > int main()
> > {
> >     test s = { 1 };
> >     test d = { 2 };
> >     std::memcpy( &d, &s, sizeof( test ) );
> > }
> >
> > I assume you consider test to be a valid POD-struct. Please correct me
> > if I am wrong.
> >
> > Do you consider that the memcpy line is valid according to 3.9/3 of the
> > standard?
>
> No, it's not. The memcpy line is an example of undefined behavior.

I agree that it's clearly undefined behaviour, but that's not what I asked.
>From what you write below, I think perhaps you meant to answer "Yes,
but..."?

> I believe this to be a very interesting observation, as 3.9/3 allows what
is
> forbidden by 7.1.5.1/4 if the value of an object of a POD class type
> containig a const non-static data member is copied into another object of
> the same type with 'memcpy'. This is not the only problem that arises with
> PODs and the guarantees given in 3.9/2-3, see issue 273 at:
> http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html
>
> I would encourage you to submit a Defect Report.

OK, although the last one I submitted seems to have disappeared into a black
hole...

I don't think I can do it for a week or so as I'm busy. If you want to do it
in the meantime, feel free.

Many thanks for clarifying things greatly.

Kind regards

Garry Lancaster
Codemill Ltd
mailto: glancaster@codemill.net
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "glancaster" <glancaster@ntlworld.com>
Date: Wed, 30 May 2001 15:39:07 GMT
Raw View
Andrei Iltchenko:
> A POD-struct can contain a const member sub-object, so can a
> POD-union. It's just that in that case, when defining an object of
> such a type you have to use a brace-enclosed initializer list and
> provide an initializer for the const member sub-object.
>
> It follows that:
> 1. You cannot create objects of such types using a new-expression;
> 2. In the case of a POD-union if the const member sub-object is not
> the first member of the union, there's no well-formed way of creating
> an object of this union type.
>
> The fact that POD class types can have const member sub-object has a
> reflection in the Standard -- read 5.3.4/15 bullet 1, sub-bullet 2.

Weird. This really only mentions const members in passing, but it is the
only part of the standard I have found that talks about allowing or
disallowing const sub-objects of POD-structs at all!

I assumed there was a prohibition *somewhere* since both my compilers
(MSVC++6 and Borland C++ Builder 5) don't accept structs with const members
and no ctor, even if I initialise them with an initializer list.

So, I'm still confused. If it is as you say it is then both compilers are
wrong as is paragraph 3.9/3 of the standard.

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: iltchenko@yahoo.com (Andrei Iltchenko)
Date: Tue, 29 May 2001 17:19:40 GMT
Raw View
"Bo-Staffan Lankinen" <bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com> wrote in message news:<9ero0t$rmjq$1@ID-47792.news.dfncis.de>...
> > This makes me think that the case was not considered when writing 3.9/3,
> > which appears to guarantee memcpy is always a valid way of copying one
> > variable of POD type T to another.
>
> A POD-struct can't contain a const sub-object member because a POD-struct is
> an aggregate, which in turn means it can't have any user defined
> constructors.

A POD-struct can contain a const member sub-object, so can a
POD-union. It's just that in that case, when defining an object of
such a type you have to use a brace-enclosed initializer list and
provide an initializer for the const member sub-object.

It follows that:
1. You cannot create objects of such types using a new-expression;
2. In the case of a POD-union if the const member sub-object is not
the first member of the union, there's no well-formed way of creating
an object of this union type.

The fact that POD class types can have const member sub-object has a
reflection in the Standard -- read 5.3.4/15 bullet 1, sub-bullet 2.


Cheers,

Andrei Iltchenko.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Bo-Staffan Lankinen" <bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com>
Date: Mon, 28 May 2001 09:57:04 GMT
Raw View
> This makes me think that the case was not considered when writing 3.9/3,
> which appears to guarantee memcpy is always a valid way of copying one
> variable of POD type T to another.

A POD-struct can't contain a const sub-object member because a POD-struct is
an aggregate, which in turn means it can't have any user defined
constructors.

Bo-Staffan


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "glancaster" <glancaster@ntlworld.com>
Date: Mon, 28 May 2001 23:00:25 GMT
Raw View
Bo-Staffan Lankinen:
> A POD-struct can't contain a const sub-object member because a POD-struct
is
> an aggregate, which in turn means it can't have any user defined
> constructors.

Many thanks. You are right. The meaning of the term "aggregate" (8.5.1) was
the bit I misunderstood. This meant my example wasn't the POD-struct I
thought it was.

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Scott Robert Ladd" <scott@coyotegulch.com>
Date: Fri, 25 May 2001 20:12:18 GMT
Raw View
The memcpy() functions has no knowledge of constness; it takes two memory
addresses and copies a set number of bytes from one place to another. Those
pointers could point to POD types, or C++ objects, or even chucks of raw
memory; long ago, I used memcpy() to read and write video memory at physical
addresses.

Without knowledge of types or object boundaries, memcpy has no way to know
that the following might be dangerous:

    float f(0.0);
    long l(-1);
    memcpy(&f,&l,sizeof(float));

The above code fragment will execute fine (assuming both f and l are 32 bit
values). Types (in which const is a factor) have no meaning to memcpy and
its relatives.

--
Scott Robert Ladd
Master of Complexity, Destroyer of Order and Chaos
http://www.coyotegulch.com


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "glancaster" <glancaster@ntlworld.com>
Date: Sun, 27 May 2001 02:58:18 GMT
Raw View
Scott Robert Ladd:
> The memcpy() functions has no knowledge of constness;

It does for fundamental types. Try:

int src = 1;
const int dst = 2;
memcpy( &dst, &src, sizeof(T) );

This will fail to compile because dst is const. You will need an unsafe cast
to shut the compiler up, in which case you deserve all you get.

The only time memcpy will assign to a const without an unsafe cast is when
an class, struct or union has a const member. This is uncommon for PODs
because:

(a) const members need to be initialised by a ctor-initializer, so the POD
has to have a ctor (12.6.2/4).

(b) The type, although it must have at least one ctor, cannot have a dtor or
user-defined copy assignment, otherwise it won't be a POD any more (9/4).

This makes me think that the case was not considered when writing 3.9/3,
which appears to guarantee memcpy is always a valid way of copying one
variable of POD type T to another.

[snip]

> Without knowledge of types or object boundaries, memcpy has no way to know
> that the following might be dangerous:
>
>     float f(0.0);
>     long l(-1);
>     memcpy(&f,&l,sizeof(float));

[snip]

The difference between this and example I gave is in whether the standard
guarantees it is valid. It doesn't for your example, it does for mine, at
least as far as I can see. Did you read 3.9/3 before replying?

Of course, I could be misinterpreting it, in which case I'd be glad for
someone to explain my mistake.

I know it seems at first glance like a beginner's question about const
and/or memcpy, but actually (I hope) it's a little bit more subtle than
that.

Kind regards

Garry Lancaster
Codemill Ltd
mailto << "glancaster" << at << "codemill" << dot << "net";
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "glancaster" <glancaster@ntlworld.com>
Date: Thu, 24 May 2001 19:09:38 GMT
Raw View
Hi all,

Following 9/4 this seems to me to be a POD (actually a POD-struct):

struct test
{
    test(int i) : i_( i ) {}
    const int i_;
};

I think 3.9/3 implies this is required to work:

test* pT1 = new test(1);
test* pT2 = new test(2);
memcpy( pT2, pT1, sizeof(test) );

The memcpy of course changes the value of the const member, surely something
that shouldn't be allowed.

What have I missed? Or is there a problem with the standard here? If so,
which bit?

Kind regards

Garry Lancaster
Codemill Ltd
mailto << "glancaster" << at << "codemill" << dot << "net";
Visit our web site at http://www.codemill.net




---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]