Copying struct with array

D

David Rasmussen

If I have this

struct S
{
int arr[5];
};

and I do this:

S s1,s2;

....

s1 = s2;

what happens?

Normally, array assignments aren't possible/allowed. If I do s1.arr =
s2.arr I get a compiler error. If I do s1 = s2 it compiles fine. And it
even seems like the array is getting copied, not just the pointer to the
start of the array, at least with g++.

Is there any difference in semantics here betweeen C and C++?

/David
 
S

Siemel Naran

struct S
{
int arr[5];
};
s1 = s2;

what happens?

Normally, array assignments aren't possible/allowed. If I do s1.arr =
s2.arr I get a compiler error. If I do s1 = s2 it compiles fine. And it
even seems like the array is getting copied, not just the pointer to the
start of the array, at least with g++.

Is there any difference in semantics here betweeen C and C++?

Yes, the assignment copies the array contents, in both C and C++. Same
thing for the copy constructor.
 
A

Andrey Tarasevich

David said:
If I have this

struct S
{
int arr[5];
};

and I do this:

S s1,s2;

...

s1 = s2;

what happens?

The entire object gets copied. The array is a subobject of that object,
which means that it gets copied too.
Normally, array assignments aren't possible/allowed. If I do s1.arr =
s2.arr I get a compiler error.

Array assignment is possible. Arrays are aggregates, just like structs
are. Technically, they can be copied the same way structs are. But it is
not allowed at language level for purely historical reasons.
If I do s1 = s2 it compiles fine. And it
even seems like the array is getting copied, not just the pointer to the
start of the array, at least with g++.

What pointer? There's no "pointer to the start of the array" in this
example.
Is there any difference in semantics here betweeen C and C++?

No.
 
D

David Rasmussen

Andrey said:
Array assignment is possible. Arrays are aggregates, just like structs
are. Technically, they can be copied the same way structs are. But it is
not allowed at language level for purely historical reasons.

Wow. You learn something new everyday... I'm not actually a novice C++
programmer (well, maybe I am after all).

So, just to be clear:

s1.arr = s2.arr isn't possible

but s1 = s2 is?

That's weird!

/David
 
D

David Rasmussen

Siemel said:
Yes, the assignment copies the array contents, in both C and C++. Same
thing for the copy constructor.

It's really weird that the compiler will copy the array implicitly, but
not explicitly. As in s1.arr = s2.arr;

/David
 
K

Karl Heinz Buchegger

David said:
It's really weird that the compiler will copy the array implicitly, but
not explicitly. As in s1.arr = s2.arr;

If I remember correctly, the same was true with structures in ancient
times (K&R C). It's just that the rules have been changed for structs
but not for arrays. I guess to much code would have been broken at
the time of change.
 
J

John Harrison

David Rasmussen said:
It's really weird that the compiler will copy the array implicitly, but
not explicitly. As in s1.arr = s2.arr;

Not really, it copies each member of the array like this

for (int i = 0; i< 5; ++i)
s1.arr = s2.arr;

Nothing wierd about it, that's the definition of a default copy
ctor/assignment op, they do a memberwise copy.

john
 
D

David Rasmussen

John said:
Not really, it copies each member of the array like this

for (int i = 0; i< 5; ++i)
s1.arr = s2.arr;

Nothing wierd about it, that's the definition of a default copy
ctor/assignment op, they do a memberwise copy.


Sure, but then s1.arr = s2.arr should do the same.

s1 = s2 does a memberwise copy of the structs. That is, each member is
copied. But in the case of the array, this copying is a "magical"
operator that we can't access any other way.
What happens if we copy a struct that has a member that has a private
copy constructor and a private assignment operator?
Like:

class M
{
// private copy constructor and assignment operator
};

struct S
{
M m;
};

S s1,s2;

s1 = s2;

In this case, s1.m = s2.m isn't possible. So I wouldn't expect s1 = s2
to be.

/David
 
J

John Harrison

David Rasmussen said:
John said:
Not really, it copies each member of the array like this

for (int i = 0; i< 5; ++i)
s1.arr = s2.arr;

Nothing wierd about it, that's the definition of a default copy
ctor/assignment op, they do a memberwise copy.


Sure, but then s1.arr = s2.arr should do the same.


It can't, its just history

void f(int a[6])
{
}

int main()
{
int b[6];
f(b);
}

What you are saying is that given this code array b should be copied
wholesale to the array parameter a. That would be logical, but unfortunately
since the dawn of time C (and hence C++) has defined different behaviour for
that code (a is really a pointer, array decays to pointer to the first
element etc etc). Too late to change now.

I think the original decision to treat arrays in this special way was made
because of concerns about the efficiency of copying large arrays.

But structs are different because in the original C

void f(struct S a)
{
}

int main()
{
struct S b;
f(b);
}

was just plain illegal. So when it was decided that actually being able to
copy structs was a useful thing, there wasn't a legacy of C code that
defined different behaviour.

john
 
J

JKop

David Rasmussen posted:
Normally, array assignments aren't possible/allowed. If I do s1.arr =
s2.arr I get a compiler error.


That's exactly like writing:


5 = 6;

"Hello" = "Goodbye";


As I'm about to explain:


unsigned int Ages[7];



Now, if I write:


unsigned int k = Ages[0];


Then the value stored in the variable entitled "Ages[0]" gets copied to the
variable entitled "k". No problemo. Now... look at the following:

k = Ages;

"Ages" written on it's own, without an array index, is exactly like writing
"&Ages[0]", ie. it's equal to the address of the first variable in the
array. Now, take your example:

s1.ar = s2.ar;


That is equal to:

&s1.ar[0] = &s2.ar[0];


That's exactly like writing:

unsigned int k = 4;
&k = 27873;

You're not changing the value of a variable at all! You're trying to change
the address of a variable! Self-explanatory I hope!

If I do s1 = s2 it compiles fine.


unsigned int a = 5;
unsigned int b = 6;

a = b;

b = a;

&a = &b; //ERROR


All you are doing is copying memory! As so:

S s1;
S s2;

s1 = s2;

s2 = s1;

&s1 = &s2; //ERROR




Now, let's try solve your problemo:

unsigned int Cats[48];
unsigned int Dogs[48];

To copy the whole lot, you'd have to do:

Cat[0] = Dog[0];
Cat[1] = Dog[1];
Cat[2] = Dog[2];
Cat[3] = Dog[3];

Why do we have to do this? Because there's no variable called "Cat", nor is
there a varible called "Dog". There's a variable called "Cat[0]" alright, as
is there a variable called "Dog[0]". So why is the following valid?:

unsigned int* pCats = Cats;

There's no reason! It makes no sense at all! Someone just decided it was
more convenient than:

unsigned int* pCats = &Cats[0];


I'll get to the point, how should we do it? Well, what you've done is
actually very clever and it's the best thing I've ever seen for doing it!
Take the following:

void RegisterName(const char* const pNameToRegister)
{
//Here, we need to keep a record of the name, so we copy it.
//Normally, I would use strcpy, as follows:

char NameBuffer[30];
strcpy(NameBuffer, pNameToRegister);

//But you've come up with a brilliant idea!!

struct StringCopierStructureBuffer
{
char NameBuffer[30];
};

StringCopierStructureBuffer* pInput = (StringCopierStructureBuffer*)
pNameToRegister;

StringCopierStructureBuffer pStored;

pStored = *pInput;

//We don't need strcpy! We can use this with any sort of array!

//I wrote the above code in about 5 mins and there's likely to be a
//thousand errors in it, but you get the picture.

}



-JKop
 
A

Andrey Tarasevich

JKop said:
Now, take your example:

s1.ar = s2.ar;

That is equal to:

&s1.ar[0] = &s2.ar[0];

That's exactly like writing:

unsigned int k = 4;
&k = 27873;

You're not changing the value of a variable at all! You're trying to change
the address of a variable! Self-explanatory I hope!
...

This doesn't really explain much. Yes, the standard array-to-pointer
conversion is the immediate formal reason why such code won't compile,
but the _real_ question is why array assignment (and array copying)
contexts were not excluded from the list of contexts where
array-to-pointer conversion is applied. Today there is no formal reason
for it to be this way, although there probably was one a rather long
time ago.

There is no technical problems with requiring the language to perform
array assignment in

s1.ar = s2.ar;

But doing this will break the compatibility with previous version of
language specification.

Note also that one specific array-related context does actually copy arrays:

char lpsz[] = "Hello world";
 

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,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top