Default ctor, etc generated by compiler for structs?

V

Victor Bazarov

JohnQ said:
That's interesting. Apparently "a struct is a struct" hardly ever! Oh
wait, does C do memberwise copy of structs also or bitwise?

How would you determine the difference? If your members are all POD,
which means they essentially all boil down to built-in types, and
there are no references among them, their copy semantics are usually
just like "bitwise" or "bytewise" or "memcpy-like".

V
 
B

BobR

JohnQ wrote in message...
I was pondering the technique of restricting default constructor, copy
constructor, assignment operator though and its validity for structs as well
as classes:

class A{
A(); // disallow def construction
A(const A&); // disallow copy construction
const A& operator=(const A&); // disallow assignment
public
int data_member;
A(int arg) : data_member(arg) {}
};

struct B{

private: // to be consistant with the class A
B(); // disallow def construction
B(const B&); // disallow copy construction
const B& operator=(const B&); // disallow assignment

public:
int data_member; // public by default

B(int arg) : data_member( arg ){}
};

If I disallow the stuff in struct B, it acts less like a C struct, yes?
John

A 'C++' struct is NOT a 'C' struct. It can act like a 'C' struct if that's
the way you design it.

With the 'private:' and 'public:' I added to 'B', 'A' and 'B' are the same.
Try using 'A' and 'B', then swap the 'class' and 'struct', try it again. Can
you see any difference?

You can even do:

struct AA{ virtual ~AA(){} };
class BB : public AA{/*stuff*/};
BB bb;

class CC{ public: virtual ~CC(){} };
struct DD : public CC{/*stuff*/};
DD dd;

Use 'public/private/protected' for inheritance as needed, as well as inside
the class/struct.

Try it!
 
J

JohnQ

Victor Bazarov said:
JohnQ said:
[..]
struct B
{
B(); // disallow def construction
B(const B&); // disallow copy construction
const B& operator=(const B&); // disallow assignment

int data_member; // public by default

B(int arg)
: data_member(arg) {}
};

If I disallow the stuff in struct B, it acts less like a C struct,
yes?

As soon as you add a c-tor to B, it stops being a POD. Whether you
"disallow the stuff" or not does not matter after that, it's not
"a C struct" any more.

But for all practical purposes, it acts like one?

John
 
I

Ian Collins

JohnQ said:
Victor Bazarov said:
JohnQ said:
[..]
struct B
{
B(); // disallow def construction
B(const B&); // disallow copy construction
const B& operator=(const B&); // disallow assignment

int data_member; // public by default

B(int arg)
: data_member(arg) {}
};

If I disallow the stuff in struct B, it acts less like a C struct,
yes?

As soon as you add a c-tor to B, it stops being a POD. Whether you
"disallow the stuff" or not does not matter after that, it's not
"a C struct" any more.

But for all practical purposes, it acts like one?
No, it does not. You have added a constructor. Compare

struct X {
int x;
};

X x = {2};

and

struct Y {
int x;
Y() {}
};

Y y = {2};
 
J

JohnQ

BobR said:
JohnQ wrote in message...

private: // to be consistant with the class A


A 'C++' struct is NOT a 'C' struct.

I'm trying to figure out when/if I can rely on a C++ to be "C-struct-like".
(Else I'll use the wrapper style I also posted... which may be easier than
trying to figure out what goes on behind the scenes).
It can act like a 'C' struct if that's the way you design it.

I thought all the above thingsare like a C struct. I'm just "worried" about
the layout and size for bitwise copying and such.
With the 'private:' and 'public:' I added to 'B', 'A' and 'B' are the
same.

I realize that. But you made struct B "class-like". I'd like some ensurance
the other way: making classes struct-like (or rather, knowing when they are
such).
Try using 'A' and 'B', then swap the 'class' and 'struct', try it again.
Can
you see any difference?

Of course not, i wouldn't expect to.
You can even do:

struct AA{ virtual ~AA(){} };
class BB : public AA{/*stuff*/};
BB bb;

class CC{ public: virtual ~CC(){} };
struct DD : public CC{/*stuff*/};
DD dd;

Use 'public/private/protected' for inheritance as needed, as well as
inside
the class/struct.

Try it!

Why? It's not what I'm concerned about. I'm "worried" about what the thing
looks like in memory, not elementary access specifier stuff (unless it
affects the layout making it different that a struct).

John
 
J

JohnQ

Victor Bazarov said:
What's "an identical class"? A class with the same order of its
members, all declared public? No difference.

I'm concerned about blasting it around like a C struct. That and keeping the
size the same.
Conceptually, every type has a destructor (or you can say that it
does, since you can call it). The standard has s concept of
"a pseudo-destructor call", which means that any type has at least
a pseudo-destructor. In my book you can say that a concept of
a destructor exists for every type.

Understood. That's what the constructor/copy constructor/assignment
operator/destructor do as together: make classes (or structs) behave like
built-in types.
There is no code where the
CPU is led to perform some actions when an object of a POD type is
disposed of, yes. In that sense, a POD type does not have a d-tor.
So, conceptually, yes, physically, no.

See, now I think someone else said that those things would be generated
(maybe they didn't). I had a feeling they weren't. So that's saying
restricting those things in structs is unnecessary.

Hmmm... now if a class is defined just like a struct but has the class'
Nope. If we agree to substitute the words "C struct" with "POD",
then the Standard says that as soon as you add a user-defined c-tor,
it's not a POD any more, so not all non-virtual member functions
are "harmless" as far as POD-ness is concerned.

So I lose all guarantees about the layout and size of thing (it's
implemenation-specific what the thing looks like in memory?)?
Here, 'B' is not a POD class.

OK. So, don't use it like a C struct ever?
You mean

StructWrapper(int val) { a_struct.data = val; }

, right?
Yes.


Nothing in the Standard says what the layouts are. We cannot rely on
their being the same.

You see what I'm trying to indicate though right? That I want to be able to
memcpy these things and the like, based upon their size.
That doesn't matter.

It was actually a question. And when it deviates from that. The moment I
use 'private' in a struct, all bets are off? Meaning there could be
something tucked between the start of the object in memory and the first
data member?
Again, there is no way to "guarantee" what's not defined. There is
no definition of a complete class layout in the Standard.

What about a struct with constructor?
What about a struct with just POD data members?
Well, calling 'memcpy' upon copy-constructing an object is up to the
implementation. There is no way to know exactly what they do with
POD, most likely 'memcpy', or 'memmove', or some such. However, it
would be safer to assume that "memberwise copy" is performed, which
means that copy semantics for each member (provided they exist) are
invoked.

OK. Someone else said that memberwise copy was done.
No, not always. For example, it's possible to copy-construct
a reference, but it's not possible to assign one, so if your class
has a data member that is a reference (it does make it non-POD, BTW),
then the copy c-tor can (and will) be generated but the copy
assignment op cannot (and will not) be.

That's getting away from "struct with only POD data members", and that is
what I'm really only concerned with.

John
 
J

JohnQ

Ian Collins said:
JohnQ said:
Victor Bazarov said:
JohnQ wrote:
[..]
struct B
{
B(); // disallow def construction
B(const B&); // disallow copy construction
const B& operator=(const B&); // disallow assignment

int data_member; // public by default

B(int arg)
: data_member(arg) {}
};

If I disallow the stuff in struct B, it acts less like a C struct,
yes?

As soon as you add a c-tor to B, it stops being a POD. Whether you
"disallow the stuff" or not does not matter after that, it's not
"a C struct" any more.

But for all practical purposes, it acts like one?
No, it does not. You have added a constructor.

I meant in memory. I still have the same question as when I started I guess:
"when does a struct stop being a struct?". And by that, I mean the
guarantees I have for using it in a memcpy call for example.

struct A
{
int val;
};

class B
{
int val;

B(int x){ val = x; }
};

Is the following always trouble (?):

memcpy(&A, &B, sizeof(A));
Compare

struct X {
int x;
};

X x = {2};

and

struct Y {
int x;
Y() {}
};

Y y = {2};

Yeah, but that's my issue (I know I didn't state it very directly probably).
I'm not really worried about the behavioural diffences.

John
 
I

Ian Collins

JohnQ said:
I'm trying to figure out when/if I can rely on a C++ to be
"C-struct-like".

It has been clearly explained elsethread.

If you want a struct to act like a C struct, use a struct that's legal C.

Or are you just being obtuse?
 
J

JohnQ

Ian Collins said:
It has been clearly explained elsethread.

If you want a struct to act like a C struct, use a struct that's legal C.

Or are you just being obtuse?

:p

I'm still not sure "when I can get away with it" though. I was kind of under
the impression that I could "get away with it". Perhaps not. Maybe
jettisoning C roots is not possible nor desireable.

John
 
C

Clark Cox

:p

I'm still not sure "when I can get away with it" though. I was kind of
under the impression that I could "get away with it". Perhaps not.
Maybe jettisoning C roots is not possible nor desireable.

What are you not sure about? As Ian just said, essentially, if you
write a struct that would be legal in both C and C++, then it will
behave just like a C struct. That is when you can "get away with it".
 
J

JohnQ

Clark Cox said:
What are you not sure about? As Ian just said, essentially, if you write a
struct that would be legal in both C and C++, then it will behave just
like a C struct. That is when you can "get away with it".

So my StructWrapper class is my avenue to program like I want to (in that
pattern)?

John
 
B

Bo Persson

JohnQ wrote:

::: Conceptually, every type has a destructor (or you can say that it
::: does, since you can call it). The standard has s concept of
::: "a pseudo-destructor call", which means that any type has at least
::: a pseudo-destructor. In my book you can say that a concept of
::: a destructor exists for every type.
::
:: Understood. That's what the constructor/copy constructor/assignment
:: operator/destructor do as together: make classes (or structs)
:: behave like built-in types.
::
::: There is no code where the
::: CPU is led to perform some actions when an object of a POD type is
::: disposed of, yes. In that sense, a POD type does not have a
::: d-tor. So, conceptually, yes, physically, no.
::
:: See, now I think someone else said that those things would be
:: generated (maybe they didn't). I had a feeling they weren't. So
:: that's saying restricting those things in structs is unnecessary.

What Victor means with "conceptually" is that the destructor for a POD
doesn't have to do anything. If you look at the machine code generated
by the compiler, you will not find anything.

Does that mean that it is not there, or just that the compiler inlined
an empty function? :)

:: Hmmm... now if a class is defined just like a struct but has the
:: class' keyword, will the <whatever you call that group of
:: functions> be generated always?
::

A class and a struct is the same, except for the need (or non-need) of
the keyword public.


:::: OK, so from what I gather, the compiler may or may not generate
:::: the functions/operators depending on the data members. Is it
:::: that if there is any non-POD data member, then the
:::: functions/operators get generated? Is it always the full set
:::: (?): default constructor, copy constructor, assignment operator,
:::: (destructor?).
:::
::: No, not always. For example, it's possible to copy-construct
::: a reference, but it's not possible to assign one, so if your class
::: has a data member that is a reference (it does make it non-POD,
::: BTW), then the copy c-tor can (and will) be generated but the copy
::: assignment op cannot (and will not) be.
::
:: That's getting away from "struct with only POD data members", and
:: that is what I'm really only concerned with.

But this is important. One of the basic requirements of a POD is that
it can only have POD members.

What doesn't matter is if you call it a struct or a class.


Bo Persson
 
B

Bo Persson

JohnQ wrote:
::
:: I meant in memory. I still have the same question as when I
:: started I guess: "when does a struct stop being a struct?".

I think this is you basic problem! The standard says that certain
structures are PODs. Everything else is not.

8.5.1 Aggregates
"An aggregate is an array or a class (clause 9) with no user-declared
constructors (12.1), no private or protected non-static data members
(clause 11), no base classes (clause 10), and no virtual functions
(10.3)."

9 Classes
"A POD-struct is an aggregate class that has no non-static data
members of type non-POD-struct, non-POD-union (or array of such types)
or reference, and has no user-defined copy assignment operator and no
user defined destructor."

If you fullfill ALL the requirements, you are a POD. If you miss only
one, you are not.


:: And by
:: that, I mean the guarantees I have for using it in a memcpy call
:: for example.
::
:: struct A
:: {
:: int val;
:: };
::
:: class B
:: {
:: int val;
::
:: B(int x){ val = x; }
:: };
::
:: Is the following always trouble (?):
::
:: memcpy(&A, &B, sizeof(A));
::

It is trouble in that the standard doesn't guarantee that it should
work. It just might anyway, but we don't know.

We cannot test it either, because the standard just doesn't say what
should happen. So different things could happen different times, or
with different compiler options, or definitely with different
compilers.


Bo Persson
 
B

Bo Persson

JohnQ wrote:

::: Perhaps, but it's not defined in C++. Of more direct relevance to
::: the OP though is that, regardless of whether we're all happy with
::: that definition of "bitwise copy", it's not what happens in the
::: implicitly- defined copy constructor, which does a memberwise
::: copy.
::
:: That's interesting. Apparently "a struct is a struct" hardly ever!
:: Oh wait, does C do memberwise copy of structs also or bitwise?

In C there is not much of a difference!

Here's something else:

In C and C++, the *compiler* is allowed to do a bitwise copy whenever
it knows that it will work (and is better in some way). This means
that the compiler generated copy constructor and assignment operator
might look like a memcpy (or better!), even for a non-POD class.

It is just you, the programmer, that cannot do this, because there are
no guarantees in the standard that it will work always. The compiler
knows all the special cases, and is allowed to take advantage of this
knowledge.


Bo Persson
 
J

James Kanze

Ian Collins said:
JohnQ said:
JohnQ wrote:
[..]
struct B
{
B(); // disallow def construction
B(const B&); // disallow copy construction
const B& operator=(const B&); // disallow assignment
int data_member; // public by default
B(int arg)
: data_member(arg) {}
};
If I disallow the stuff in struct B, it acts less like a C struct,
yes?
As soon as you add a c-tor to B, it stops being a POD. Whether you
"disallow the stuff" or not does not matter after that, it's not
"a C struct" any more.
But for all practical purposes, it acts like one?
No, it does not. You have added a constructor.
I meant in memory. I still have the same question as when I
started I guess: "when does a struct stop being a struct?".

When it's compiled with a C++ compiler? What do you mean by "a
struct", exactly? In C++, even a POD struct is a class type.
And by that, I mean the guarantees I have for using it in a
memcpy call for example.

If the class has a constructor, it can't be memcpy'ed, at least
according to the standard.
struct A
{
int val;
};
class B
{
int val;
B(int x){ val = x; }
};
Is the following always trouble (?):
memcpy(&A, &B, sizeof(A));

The standard says it is undefined behavior, although you may get
away with it.
 
J

James Kanze

What's "an identical class"? A class with the same order of its
members, all declared public? No difference.

Actually, the standard has a definition for "an identical
class". It's called the "one definition rule". But I rather
doubt that this is what JohnQ is talking about. (Of course, I'm
not too sure what he's talking about. He seems to avoid precise
vocabulary intentionally, just to create confusion.)

Anyway, someone else has already posted the definition of POD,
which is about the only real categorization which is recognized
by the standard. (And I know you know that.)
Conceptually, every type has a destructor (or you can say that it
does, since you can call it). The standard has s concept of
"a pseudo-destructor call", which means that any type has at least
a pseudo-destructor. In my book you can say that a concept of
a destructor exists for every type. There is no code where the
CPU is led to perform some actions when an object of a POD type is
disposed of, yes. In that sense, a POD type does not have a d-tor.
So, conceptually, yes, physically, no.

The standard doesn't talk about "pseudo-destructors". What I
think you're getting at is that you can call the destructor for
any type, e.g. something like p->~int() is legal. (Obviously,
no one does this directly. But a lot of template code results
in it, and in pre-template days, it ended up generated by
<generic.h> just about any time you wrote a container class.)
Explicitly calling the destructor on a type such as int, which
doesn't have a destructor, is a no-op.

A second point to keep in mind is that a class type (i.e. any
type defined by means of the keywords class, struct or union)
always has a destructor. If you don't provide one, the compiler
does. However, a "trivial destructor" doesn't prevent the type
from being a POD. The standard also defines very rigorously
when a destructor is trivial; a user defined destructor is never
trivial (but the compiler generated one is not always trivial
either).
Well, calling 'memcpy' upon copy-constructing an object is up to the
implementation. There is no way to know exactly what they do with
POD, most likely 'memcpy', or 'memmove', or some such. However, it
would be safer to assume that "memberwise copy" is performed, which
means that copy semantics for each member (provided they exist) are
invoked.

According to the standard, the semantic is always member-wise
copy. As you know, of course, the compiler can do anything it
wishes as long as the observable behavoir of the program is "as
if" memberwise copy took place. In practice, there are probably
a lot of classes (not even always POD's) in which the compiler
will effectively generate the equivalent of a memcpy, because it
can determine that doing so, instead of literally doing a
memberwise copy, will not result in any difference in the
observable behavior.
 
C

Clark Cox

So my StructWrapper class is my avenue to program like I want to (in
that pattern)?

No. Your StructWrapper and B classes have user defined constructors;
therefore they are not POD types. There is no way to guarantee that
instances of a POD type and a non-POD type will be laid out identically
in memory.
 
J

Jim Langston

JohnQ said:
That's what I was thinking. I wasn't sure if the compiler generates those
things for a POD struct. Are you sure?

The only real difference between a class and a structure is that structure
is public by default, class is private. Other than that, they act exactly
the same. So, yes, I am positive that the compiler will create the 4.
To prevent those things from happening unknowingly for what could be a
non-POD.

Right, hence my reasoning that if you are sure it's POD then you wouldn't
need them.

Personally, I use struct for POD, class otherwise. And, yes, if I make a
structure that becomes non POD, I change it to a class.
 
J

JohnQ

Bo Persson said:
JohnQ wrote:
::
:: I meant in memory. I still have the same question as when I
:: started I guess: "when does a struct stop being a struct?".

I think this is you basic problem! The standard says that certain
structures are PODs. Everything else is not.

8.5.1 Aggregates
"An aggregate is an array or a class (clause 9) with no user-declared
constructors (12.1), no private or protected non-static data members
(clause 11), no base classes (clause 10), and no virtual functions
(10.3)."

9 Classes
"A POD-struct is an aggregate class that has no non-static data members of
type non-POD-struct, non-POD-union (or array of such types) or reference,
and has no user-defined copy assignment operator and no user defined
destructor."

OK, then POD-struct = Aggregate (8.5.1) rules + aggregate class (9) rules:

1. No user-defined constructor, copy constructor, assignment operator,
destructor.
2. No virtual functions.
3. No base classes.
4. No private or protected non-static data members .
5. No non-POD data members.
6. No reference data members.

Got it. Apparently, I'll be (re)writing a lot more StructWrapper-type
classes.
If you fullfill ALL the requirements, you are a POD. If you miss only one,
you are not.


:: And by
:: that, I mean the guarantees I have for using it in a memcpy call
:: for example.
::
:: struct A
:: {
:: int val;
:: };
::
:: class B
:: {
:: int val;
::
:: B(int x){ val = x; }
:: };
::
:: Is the following always trouble (?):
::
:: memcpy(&A, &B, sizeof(A));
::

It is trouble in that the standard doesn't guarantee that it should work.
It just might anyway, but we don't know.
We cannot test it either, because the standard just doesn't say what
should happen. So different things could happen different times, or with
different compiler options, or definitely with different compilers.

OK. Then "bad" to do.

John
 
J

JohnQ

Ian Collins said:
JohnQ said:
JohnQ wrote:
[..]
struct B
{
B(); // disallow def construction
B(const B&); // disallow copy construction
const B& operator=(const B&); // disallow assignment
int data_member; // public by default
B(int arg)
: data_member(arg) {}
};
If I disallow the stuff in struct B, it acts less like a C struct,
yes?
As soon as you add a c-tor to B, it stops being a POD. Whether you
"disallow the stuff" or not does not matter after that, it's not
"a C struct" any more.
But for all practical purposes, it acts like one?
No, it does not. You have added a constructor.
I meant in memory. I still have the same question as when I
started I guess: "when does a struct stop being a struct?".

"When it's compiled with a C++ compiler? What do you mean by "a
struct", exactly? In C++, even a POD struct is a class type."

But apparently, the moment you add something "class-like" to the struct,
it's not a POD anymore.
And by that, I mean the guarantees I have for using it in a
memcpy call for example.

"If the class has a constructor, it can't be memcpy'ed, at least
according to the standard."

I wasn't sure about that until the posts in this thread solidified it for
me.
struct A
{
int val;
};
class B
{
int val;
B(int x){ val = x; }
};
Is the following always trouble (?):
memcpy(&A, &B, sizeof(A));

"The standard says it is undefined behavior, although you may get
away with it."

Yeah, I get it now. Bo Pearson's post made it official in my mind about POD
structs. There must be an official definition of POD somewhere also huh.
That would be nice to see.

John
 

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,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top