c++0x pods and constructors

D

dragan

Can C++0x PODs/aggregates have user-defined constructors and still be
PODs/aggregates? If not, why not? How about conversion operators? And what
is the difference between a POD and an aggregate anyway?
 
V

Victor Bazarov

dragan said:
Can C++0x PODs/aggregates have user-defined constructors and still be
PODs/aggregates?

From [dcl.init.aggr]:
<< 1 An aggregate is an array or a class (Clause 9) with no
user-provided constructors (12.1), no private or
protected non-static data members (Clause 11), no base classes (Clause
10), and no virtual functions (10.3). >>

So, no, once you add a user-defined c-tor, it's not an aggregate.
> If not, why not?

Because that's how it's defined. Ask in 'comp.std.c++' for the
rationale behind that definition.
> How about conversion operators?

You can have conversion operators in an aggregate (according to the
definition), if other conditions are met.
> And what
is the difference between a POD and an aggregate anyway?

And aggregate is a POD. A POD is not necessarily an aggregate.

V
 
J

Johannes Schaub (litb)

dragan said:
Can C++0x PODs/aggregates have user-defined constructors and still be
PODs/aggregates? If not, why not? How about conversion operators? And what
is the difference between a POD and an aggregate anyway?

Aggregates but not PODs, both in C++03 and C++0x:

string foo[10];
struct bar {
string baz;
};

In C++0x, you can use memcpy on trivially copyable types. POD is too strict
a requirement for this - so if you just want to use memcpy on a type for
example, making a type trivially copyable would suffice, in particular:

- has no non-trivial copy constructors (12.8),
— has no non-trivial copy assignment operators (13.5.3, 12.8), and
— has a trivial destructor (12.4).

A trivial class then is a class that is trivially copyable and that has a
trivial default constructor. F is trivial and G is trivially copyable:

struct F { Foo() = default; F(int a):a(a) { } int a; };
struct G { Foo(int a):a(a) { } int a; };

For other things, a class has to be a standard layout class. Thus is true
for "offsetof", to inspect a common initial sequence when two such structs
are in an union, etc. Look up the details in the latest draft at 9/6.

A POD is a class is trivial and a standard layout class and has no members
of non-POD etc... . Actually, i haven't found something in the c++0x
language in 2960 that still requires things to be PODs. Things either seem
to refer to standard layout classes or trivially copyable.
 
V

Vladimir Jovic

Johannes said:
dragan said:
Can C++0x PODs/aggregates have user-defined constructors and still be
PODs/aggregates? If not, why not? How about conversion operators? And what
is the difference between a POD and an aggregate anyway?

Aggregates but not PODs, both in C++03 and C++0x:

string foo[10];
struct bar {
string baz;
};

std::string (if you are referring to that here) is not POD, therefore
that structure can not be an aggregate.
In C++0x, you can use memcpy on trivially copyable types. POD is too strict
a requirement for this - so if you just want to use memcpy on a type for
example, making a type trivially copyable would suffice, in particular:

- has no non-trivial copy constructors (12.8),
— has no non-trivial copy assignment operators (13.5.3, 12.8), and
— has a trivial destructor (12.4).

A trivial class then is a class that is trivially copyable and that has a
trivial default constructor. F is trivial and G is trivially copyable:

struct F { Foo() = default; F(int a):a(a) { } int a; };

What is that default thing???
struct G { Foo(int a):a(a) { } int a; };

For other things, a class has to be a standard layout class. Thus is true
for "offsetof", to inspect a common initial sequence when two such structs
are in an union, etc. Look up the details in the latest draft at 9/6.

A POD is a class is trivial and a standard layout class and has no members
of non-POD etc... . Actually, i haven't found something in the c++0x
language in 2960 that still requires things to be PODs. Things either seem
to refer to standard layout classes or trivially copyable.


I think you got that wrong. As far as I know (might be wrong), but
agregate is defined as an array or class that has none of the following
characretistics:
1) user declared constructors
2) private or protected non-static data members
3) base classes
4) virtual functions
 
J

Johannes Schaub (litb)

Vladimir said:
Johannes said:
dragan said:
Can C++0x PODs/aggregates have user-defined constructors and still be
PODs/aggregates? If not, why not? How about conversion operators? And
what is the difference between a POD and an aggregate anyway?

Aggregates but not PODs, both in C++03 and C++0x:

string foo[10];
struct bar {
string baz;
};

std::string (if you are referring to that here) is not POD, therefore
that structure can not be an aggregate.
That has nothing to do with it not being an aggregate. Non-PODs can be
aggregates, of course. Please gimme some standard legalese to prove me wrong
:)
What is that default thing???
This is a C++0x feature, and it means that the user declared constructor
will have a default implementation (which is trivial here).
I think you got that wrong. As far as I know (might be wrong), but
agregate is defined as an array or class that has none of the following
characretistics:
1) user declared constructors
2) private or protected non-static data members
3) base classes
4) virtual functions
Yes, that's right (for c++03. For C++0x, "user declared" is changed to "user
provided", as you can declare a constructor yourself, but then default it).
So an aggregate can surely contain std::string :) However, where do i say
something contradictory?
 
J

James Kanze

From [dcl.init.aggr]:
<< 1 An aggregate is an array or a class (Clause 9) with no
user-provided constructors (12.1), no private or
protected non-static data members (Clause 11), no base classes (Clause
10), and no virtual functions (10.3). >>
So, no, once you add a user-defined c-tor, it's not an aggregate.
Because that's how it's defined. Ask in 'comp.std.c++' for
the rationale behind that definition.

The rationale is probably simply that they needed the
distinction for some reason. In C++03, the distinction is
clear: aggregates can only be initialized using the aggregate
initialization syntax; other things can't be initialized using
the aggregate initialized syntax. In C++0x, there will be a
universal initialization syntax, which works for both aggregates
and non aggregates, but the semantics are still different: when
initializing an aggregate, you specify the initializer for each
member; when initializing a non-aggregate, you specify the
arguments for a constructor.
You can have conversion operators in an aggregate (according
to the definition), if other conditions are met.
And aggregate is a POD. A POD is not necessarily an
aggregate.

Intuitively: an aggregate is determined superficially: an array
or a class with no user defined constructor, but elements of the
array or class aren't necessarily aggregates. A POD is defined
"deeply": for something to be a POD, all of its elements must be
POD's, recursively. There's more to it than that, of course.
The important difference is that whether something is an
aggregate or not determines how it is initialized (in C++03) or
what the initialization arguments mean (in C++0x). The
difference between a POD and a non-POD is that a POD has
constructors and destructors which are effectively no-ops, and
an assignment operator which is the equivalent of memcpy; this
plays a role in various contexts.
 
J

James Kanze

Johannes said:
dragan wrote:
Can C++0x PODs/aggregates have user-defined constructors
and still be PODs/aggregates? If not, why not? How about
conversion operators? And what is the difference between a
POD and an aggregate anyway?
Aggregates but not PODs, both in C++03 and C++0x:
string foo[10];
struct bar {
string baz;
};
std::string (if you are referring to that here) is not POD,
therefore that structure can not be an aggregate.

std::string is not an aggregate, but bar is. Aggregation is
determined very superficially; if the class has no user defined
constructor or private data members, it is an aggregate.
What is that default thing???

Something new to C++0x. It just means that the compiler should
use the default implementation. In this case, I suppose that
Foo is a typo for F, and it is used to say that the default
constructor is the compiler generated default (and not absent,
as it would be otherwise in the presence of other constructors).
 
J

Johannes Schaub (litb)

James said:
Something new to C++0x. It just means that the compiler should
use the default implementation. In this case, I suppose that
Foo is a typo for F, and it is used to say that the default
constructor is the compiler generated default (and not absent,
as it would be otherwise in the presence of other constructors).
Oops, yes i typo'ed. Im sorry for any confusion caused :(
 
V

Vladimir Jovic

Johannes said:
Vladimir said:
string foo[10];
struct bar {
string baz;
};
std::string (if you are referring to that here) is not POD, therefore
that structure can not be an aggregate.
That has nothing to do with it not being an aggregate. Non-PODs can be
aggregates, of course. Please gimme some standard legalese to prove me wrong
:)

I think you got that wrong. As far as I know (might be wrong), but
agregate is defined as an array or class that has none of the following
characretistics:
1) user declared constructors
2) private or protected non-static data members
3) base classes
4) virtual functions
Yes, that's right (for c++03. For C++0x, "user declared" is changed to "user
provided", as you can declare a constructor yourself, but then default it).
So an aggregate can surely contain std::string :) However, where do i say
something contradictory?

doh my mistake. An Aggregate can contain non-POD, but POD can't contain
non-POD
sorry
 
V

Victor Bazarov

James said:
Intuitively: an aggregate is determined superficially: an array
or a class with no user defined constructor, but elements of the
array or class aren't necessarily aggregates. A POD is defined
"deeply": for something to be a POD, all of its elements must be
POD's, recursively. There's more to it than that, of course.
The important difference is that whether something is an
aggregate or not determines how it is initialized (in C++03) or
what the initialization arguments mean (in C++0x). The
difference between a POD and a non-POD is that a POD has
constructors and destructors which are effectively no-ops, and
an assignment operator which is the equivalent of memcpy; this
plays a role in various contexts.

OK, so I am wrong saying that an aggregate is POD. An aggregate is POD
*iff* all of its members/elements are POD.

V
 
J

Jerry Coffin

Can C++0x PODs/aggregates have user-defined constructors and still be
PODs/aggregates? If not, why not? How about conversion operators? And what
is the difference between a POD and an aggregate anyway?

In C++ 0x, the definition of POD no longer includes the requirement
that the class be an aggregate. Instead, it introduces a couple of
new terms, "standard layout class" and "trivial class". A POD has to
be both. A user-defined constructor (by itself) does _not_ prevent
the class from being a POD -- but you have to be really careful. In
particular, a non-trivial copy constructor or non-trivial destructor
_does_ prevent it from being a trivial class (IOW, copying with
memcpy/memmove should work correctly).

A standard layout class basically says it can't have virtual
functions or virtual base classes, etc.

As long as it fits both of those sets of restrictions, it's a POD.
IOW, it _can_ have some "convenience ctors".

Obviously I'm leaving out some of the details -- see N2960, §9/5, 9/6
for the full details.
 
D

dragan

Victor said:
dragan said:
Can C++0x PODs/aggregates have user-defined constructors and still be
PODs/aggregates?

From [dcl.init.aggr]:
<< 1 An aggregate is an array or a class (Clause 9) with no
user-provided constructors (12.1), no private or
protected non-static data members (Clause 11), no base classes (Clause
10), and no virtual functions (10.3). >>

So, no, once you add a user-defined c-tor, it's not an aggregate.

I'm not sure what aggregates are good for. I think POD may be the key thing
for layout compatibility with C and probably other languages. PODs no longer
have to be aggregates in C++0x: they can have constructors, just not default
or copy constructors, and no copy assignment operator. (N2690).
You can have conversion operators in an aggregate (according to the
definition), if other conditions are met.

I assume in a POD also.
 
D

dragan

James said:
The
difference between a POD and a non-POD is that a POD has
constructors and destructors which are effectively no-ops, and
an assignment operator which is the equivalent of memcpy; this
plays a role in various contexts.

From N2960, I gather that a POD may not have user-defined: default
constructor, copy constructor, copy assignment operator, destructor. In
addition, it may not have virtual functions or virtual base classes, at most
one base class and no non-static data members in the most-derived class.
Other things too, but I find the aforementioned most important.

So, the good news is, that seemingly a POD can have constructors other
than the ones listed above and can also have a non-virtual base class. I'm
not sure what "no non-static data members in the most-derived class" means
exactly. The section needs more examples if you ask me.
 
D

dragan

Johannes said:
dragan said:
Can C++0x PODs/aggregates have user-defined constructors and still be
PODs/aggregates? If not, why not? How about conversion operators?
And what is the difference between a POD and an aggregate anyway?

Aggregates but not PODs, both in C++03 and C++0x:

string foo[10];
struct bar {
string baz;
};

In C++0x, you can use memcpy on trivially copyable types. POD is too
strict a requirement for this - so if you just want to use memcpy on
a type for example, making a type trivially copyable would suffice,
in particular:

- has no non-trivial copy constructors (12.8),
- has no non-trivial copy assignment operators (13.5.3, 12.8), and
- has a trivial destructor (12.4).

A trivial class then is a class that is trivially copyable and that
has a trivial default constructor. F is trivial and G is trivially
copyable:

struct F { Foo() = default; F(int a):a(a) { } int a; };
struct G { Foo(int a):a(a) { } int a; };

For other things, a class has to be a standard layout class. Thus is
true for "offsetof", to inspect a common initial sequence when two
such structs are in an union, etc. Look up the details in the latest
draft at 9/6.

A POD is a class is trivial and a standard layout class and has no
members of non-POD etc... . Actually, i haven't found something in
the c++0x language in 2960 that still requires things to be PODs.
Things either seem to refer to standard layout classes or trivially
copyable.

But a POD is what you want to talk with C and other languages is what I
gather.
 
D

dragan

Jerry said:
In C++ 0x, the definition of POD no longer includes the requirement
that the class be an aggregate. Instead, it introduces a couple of
new terms, "standard layout class" and "trivial class". A POD has to
be both. A user-defined constructor (by itself) does _not_ prevent
the class from being a POD -- but you have to be really careful. In
particular, a non-trivial copy constructor or non-trivial destructor
_does_ prevent it from being a trivial class (IOW, copying with
memcpy/memmove should work correctly).

A standard layout class basically says it can't have virtual
functions or virtual base classes, etc.

As long as it fits both of those sets of restrictions, it's a POD.
IOW, it _can_ have some "convenience ctors".

That's good news. That a POD can be derived from another class is also good
news. What kind of class it can be after derived though is still unclear to
me: can it have non-static data members?
Obviously I'm leaving out some of the details -- see N2960, §9/5, 9/6
for the full details.

I downloaded N2960. I like to think in terms of the things a POD can or
cannot have rather than the lingo like: trivially copyable, trivial class,
standard layout, and on and on. In another post I wrote my understanding of
what is and isn't allowed.
 
J

James Kanze

From N2960,

Note that N2960 is not the standard, but a draft for the next
version of the standard. In particular, it differs signficantly
from the current standard here (in wording---not in effect).
I gather that a POD may not have user-defined:
default constructor, copy constructor, copy assignment
operator, destructor. In addition, it may not have virtual
functions or virtual base classes, at most one base class and
no non-static data members in the most-derived class. Other
things too, but I find the aforementioned most important.

The current standard simply says that a POD must be an
aggregate; some of these requirements are part of being an
aggregate.

But you're formulating it backwards. In order to be a POD, a
class must have a trivial default constructor, a trivial copy
constructor, a trivial copy assignment operator and a trivial
destructor. If any of these is user defined, then it is by
definition non-trivial, but there are other ways for them to be
non-trivial or absent: a class with a deleted copy constructor,
for example (in the draft).
So, the good news is, that seemingly a POD can have
constructors other than the ones listed above

If you provide any constructor, the compiler no longer provides
the trivial default constructor---either you provide one (which
will be non-trivial), or there isn't one. Either way, the class
won't be a POD. (Or... I think you can tell the compiler to
provide one explicitly, and that might be trivial.)
and can also have a non-virtual base class.

Yes, but either the base class or the class itself must be
empty, which sort of makes this provision useless.
I'm not sure what "no non-static data members in the
most-derived class" means exactly. The section needs more
examples if you ask me.

It seems clear enough to me. Given a hierarchy (which may
consist of only a single class), there may be at most one class
in that hierarchy which has non-static data
members---non-static, because static data members don't affect
the layout in any way.

I think the original formulation was clearer, and the original
rules allowed an informal simplification: a POD is something you
could write in C. I'm not sure what we really gain by allowing
anything else. I understand the desire of separating "layout
compatibility" from POD-ness, since they affect different
operations (communication with other languages, memcpy-ability),
but in practice, I don't think it makes any difference.
 
J

James Kanze

Victor said:
dragan said:
Can C++0x PODs/aggregates have user-defined constructors
and still be PODs/aggregates?
From [dcl.init.aggr]:
<< 1 An aggregate is an array or a class (Clause 9) with no
user-provided constructors (12.1), no private or
protected non-static data members (Clause 11), no base classes (Clause
10), and no virtual functions (10.3). >>
So, no, once you add a user-defined c-tor, it's not an
aggregate.
I'm not sure what aggregates are good for.

Initialization syntax. The most important use is for arrays,
since you can let the compiler count the members when using
aggregate initialization, e.g.:

std::string const names[] = { "Abert", "Bertha", "Charles" ... } ;

It's also useful for structs, however, when you need static
initialization (especially for tables of structs), e.g.:

struct MapInit
{
char const* key;
int value;
};

MapInit const initTable[] =
{
{ "toto", 42 },
{ "titi", 0 },
// ...
};
I think POD may be the key thing for layout compatibility with
C and probably other languages. PODs no longer have to be
aggregates in C++0x: they can have constructors, just not
default or copy constructors, and no copy assignment operator.
(N2690).

Layout compatibility is an awkward problem. C++ can mandate a
certain number of things with regards to how the C++ compiler
lays out data, but it can't mandate anything with regards to how
other languages layout data. In the end, it's a lot like the
``extern "C"'' fiasco: C++ requires a compiler to support it,
stating that functions declared ``extern "C"'' must be callable
from C (or something along those lines). Which is all nice and
fine, but what does it mean if the platform doesn't have a C
compiler? Or if it has several C compilers, with different
calling conventions?

In practice, of course, on most small and medium sized systems
today, the system ABI is defined in terms of C, which means that
there will be a C compiler, and all C compilers will use a
commun layout and common calling conventions, so the problem
doesn't come up; C is the lowest common denominator. If you
look at it closely, you'll see that the standard doesn't
actually give any guarantees with regards to standard layout and
other languages, for the reason stated above. There may be some
advanced programming techniques which depend on standard layout,
but for the everyday user, the only really significant
distinction is whether the class could be written in C or
not---if it could, it will be accessible from C, and probably
from most other languages as well (on typical small and medium
general purpose computers---I wouldn't count on it on
mainframes, nor for that matter on embedded systems); otherwise,
it won't be. (You may, of course, add non-virtual member
functions, including conversion operators, but not constructors,
destructors or assignment operators, without causing problems.)

The other thing that is often important is whether the class is
an aggregate which supports static initialization. But in
practice, the two overlap; there are very few cases where you
can use static aggregate initialization but couldn't write the
class in C. (The presence of a pointer to member in the class
would be an example of one.)
I assume in a POD also.

A conversion operator is just an ordinary member function.
 
J

James Kanze

In C++ 0x, the definition of POD no longer includes the
requirement that the class be an aggregate. Instead, it
introduces a couple of new terms, "standard layout class" and
"trivial class". A POD has to be both. A user-defined
constructor (by itself) does _not_ prevent the class from
being a POD -- but you have to be really careful. In
particular, a non-trivial copy constructor or non-trivial
destructor _does_ prevent it from being a trivial class (IOW,
copying with memcpy/memmove should work correctly).

Attention: the requirement isn't that the class not have a
non-trivial X; it is that it have a trivial X. Thus, for
example:

struct S { S( int ); int i; };

doesn't have a non-trivial default constructor, but it doesn't
have a trivial one either, and thus, is not a POD. IIUC, in the
next version of the standard, you will be able to write:

struct S { S( int ); S() = default; int i; };

and it will have the required trivial default constructor.
A standard layout class basically says it can't have virtual
functions or virtual base classes, etc.
As long as it fits both of those sets of restrictions, it's a
POD. IOW, it _can_ have some "convenience ctors".

But IIUC, only if you ensure that it also has a trivial default
constructor. Which it won't have be default if you've provided
any other constructor.
 
J

James Kanze

Jerry Coffin wrote:
That's good news. That a POD can be derived from another class
is also good news. What kind of class it can be after derived
though is still unclear to me: can it have non-static data
members?

Only if it's empty itself.
I downloaded N2960. I like to think in terms of the things a
POD can or cannot have rather than the lingo like: trivially
copyable, trivial class, standard layout, and on and on. In
another post I wrote my understanding of what is and isn't
allowed.

The problem is that you can't express the requirements in terms
of can or cannot have. At least partially, you have to express
them in terms of "must have": a POD must have a trivial default
constructor, for example (which is not the same thing as not
having a non-trivial default constructor---you have three
possibilities: no default constructor, trivial default
constructor and non-trivial default constructor).
 
D

dragan

James said:
Note that N2960 is not the standard, but a draft for the next
version of the standard.

I know.
In particular, it differs signficantly
from the current standard here (in wording---not in effect).

Where is "here"? I thought that N2960 was pretty close to the "current state
of the art" given that it has a date of October 25, 2009 on it. Prior to
downloading N2960, I had N2800, so surely I'm a lot closer to the final
standard than I was.
The current standard simply says that a POD must be an
aggregate; some of these requirements are part of being an
aggregate.

OK, I see the disconnect now: You are talking about the current standard and
I asked about C++0x. The current standard does not concern me. Wasn't the
current one instituted in 2003?
But you're formulating it backwards. In order to be a POD, a
class must have a trivial default constructor, a trivial copy
constructor, a trivial copy assignment operator and a trivial
destructor. If any of these is user defined, then it is by
definition non-trivial,

That's why I said it couldn't have those as a practicality and for most
purposes it was "correct enough". I'm just trying to understand it, not
quote it.
but there are other ways for them to be
non-trivial or absent: a class with a deleted copy constructor,
for example (in the draft).

I kinda/sorta knew that. Someone told me that before. That when I make a
default constructor private so that default construction is not possible,
that all bets are off for it being a POD (?).
If you provide any constructor, the compiler no longer provides
the trivial default constructor---either you provide one (which
will be non-trivial), or there isn't one. Either way, the class
won't be a POD.

In the current standard or the draft? I was under the impression (and so is
at least one other poster in this thread) that PODs can have "convenience
constructors", as he put it.
(Or... I think you can tell the compiler to
provide one explicitly, and that might be trivial.)

And how can someone do that?
Yes, but either the base class or the class itself must be
empty, which sort of makes this provision useless.

Indeed it would make it useless! I didn't get that information from reading
the draft. Is it there or did I just skim over it I wonder.
It seems clear enough to me. Given a hierarchy (which may
consist of only a single class), there may be at most one class
in that hierarchy which has non-static data
members---non-static, because static data members don't affect
the layout in any way.

It just seems weird, probably for lack of my knowledge of the
intricacies/subtleties. An example would be worth a thousand words. Someone
should pen "a roadmap to the C++ standard, with examples" book. Note that
some "open" softwares have their licenses expressed also in layman's terms,
something I have found not only useful, but interesting.
I think the original formulation was clearer, and the original
rules allowed an informal simplification: a POD is something you
could write in C.

Yes! That's really my concern: where C ends and C++ starts.
I'm not sure what we really gain by allowing
anything else. I understand the desire of separating "layout
compatibility" from POD-ness, since they affect different
operations (communication with other languages, memcpy-ability),
but in practice, I don't think it makes any difference.

Nor I, for I thought they were the same thing! When I started this thread, I
included "aggregate" in my quest to understand. Then I felt that POD was
what I was really after. Live and learn! Now I think you just told me that
"layout compatibility" is the thing and that makes "POD" nebulous! Errrrgh!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,812
Latest member
GracielaWa

Latest Threads

Top