Topic: Defect Report: The definition of a POD class is overly permissive.
Author: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: 10 Mar 01 13:02:38 GMT Raw View
[Moderator's note: this defect report has been
forwarded to the C++ committee. -moderator(fjh).]
Section: 9 - Classes [class]
Submitter: Andrei Iltchenko (iltchenko@yahoo.com)
I think that the definition of a POD class in the current version of the
Standard is overly permissive in that it allows for POD classes for which a
user-defined operator function 'operator&' may be defined. Given that the
idea behind POD classes was to achieve compatibility with C structs and
unions, this makes 'Plain old' structs and unions behave not quite as one
would expect them to.
In the C language, if x and y are variables of struct or union type S that
has a member m, the following expression are allowed: '&x', 'x.m', 'x = y'.
While the C++ standard guarantees that if x and y are objects of a POD class
type S, the expressions 'x.m', 'x = y' will have the same effect as they
would in C, it is still possible for the expression '&x' to be interpreted
differently, subject to the programmer supplying an appropriate version of a
user-defined operator function 'operator&' either as a member function or as
a non-member function.
This may result in surprising effects. Consider:
// POD_bomb is a POD-struct. It has no non-static non-public data members,
// no virtual functions, no base classes, no constructors, no user-defined
// destructor, no user-defined copy assignment operator, no non-static data
// members of type pointer to member, reference, non-POD-struct, or
// non-POD-union.
struct POD_bomb {
int m_value1;
int m_value2;
int operator&()
{ return m_value1++; }
int operator&() const
{ return m_value1 + m_value2; }
};
3.9 [basic.types] paragraph 2 states:
"For any complete POD object type T, whether or not the object holds a valid
value of type T, the underlying bytes (1.7) making up the object can be
copied into an array of char or unsigned char [footnote: By using, for
example, the library functions (17.4.1.2) memcpy or memmove]. If the content
of the array of char or unsigned char is copied back into the object, the
object shall subsequently hold its original value. [Example:
#define N sizeof(T)
char buf[N];
T obj; // obj initialized to its original value
memcpy(buf, &obj, N);
// between these two calls to memcpy,
// obj might be modified
memcpy(&obj, buf, N);
// at this point, each subobject of obj of scalar type
// holds its original value
--end example]"
Now, supposing that the complete POD object type T in the example above is
POD_bomb, and we cannot any more count on the assertions made in the
comments to the example. Given a standard conforming implementation, the
code will not even compile. And I see no legal way of copying the contents
of an object of a complete object type POD_bomb into an array of char or
unsigned char with memcpy or memmove without making use of the unary '&'
operator. Except, of course, by means of an ugly construct like:
struct POD_without_ampersand {
POD_bomb a_bomb;
} obj;
#define N sizeof(POD_bomb)
char buf[N];
memcpy(buf, &obj, N);
memcpy(&obj, buf, N);
The fact that the definition of a POD class allows for POD classes for which
a user-defined 'operator&' is defined, may also present major obstacles to
implementers of the offsetof macro from <cstddef>
18.1 [lib.support.types] paragraph 5 says:
"The macro offsetof accepts a restricted set of type arguments in this
International Standard. type shall be a POD structure or a POD union (clause
9). The result of applying the offsetof macro to a field that is a static
data member or a function is undefined."
Consider a well-formed C++ program below:
#include <cstddef>
#include <iostream>
struct POD_bomb {
int m_value1;
int m_value2;
int operator&()
{ return m_value1++; }
int operator&() const
{ return m_value1 + m_value2; }
};
// POD_struct is a yet another example of a POD-struct.
struct POD_struct {
POD_bomb m_nonstatic_bomb1;
POD_bomb m_nonstatic_bomb2;
};
int main()
{
std::cout << "offset of m_nonstatic_bomb2: " << offsetof(POD_struct,
m_nonstatic_bomb2) << '\n';
return 0;
}
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 ]