Copying objects and arrays

M

Matteo Settenvini

Ok, I'm quite a newbie, so this question may appear silly. I'm using
g++ 3.3.x.
I had been taught that an array isn't a lot different from a pointer
(in fact you can use the pointer arithmetics to "browse" it). So I
expected that when I run this program, I get both c1.A and c2.A
pointing to the same address, and changing c1.A means that also c2.A
changes too.

----- BEGIN example CODE -----------

#include <iostream>
using std::cout;
using std::endl;

class C {
private :
int A[3];

public:
C() { for( int i=0; i<3; i++ ) A = 0; };
void alter() { A[1]++; };
void printA() const;
};

void
C::printA() const
{
for( int i=0; i<3; i++ )
cout << "A[" << i
<< "] is " << A
<< endl;
}

int
main( )
{
C c1, c2;

c1.alter();

c2 = c1; // Why does this also make a copy of the array??

cout << " c2 is : " << endl;
c2.printA();

c1.alter();
cout << " c2 is still : " << endl;
c2.printA();

return 0;
}

----- END example CODE -----------

Instead, a copy of the array is made, so touching c1.A doesn't affect
c2.A.

Is this a _c++ standard_ behaviour? My lucky guess is that when you
use the default copy constructor, the object at the left of the
assignment gets the memory copied bit-to-bit from the one on the right
side, like a sort of "memcpy()" happens between the two.

So an array declared as an automatic variable in c1 gets its content
copied in the new object (c2) rather than simply the address it's
pointing to, since all the space taken by the array is sequentially
allocated in memory along with other vars declared in the class scope.

Hope my english is understandable enough...
Matteo
 
M

Mike Wahler

Matteo Settenvini said:
Ok, I'm quite a newbie, so this question may appear silly. I'm using
g++ 3.3.x.
I had been taught that an array isn't a lot different from a pointer

It is very different. However the ability to use identical
syntax when using them can obsure the differences.
(in fact you can use the pointer arithmetics to "browse" it).
Yes.

So I
expected that when I run this program, I get both c1.A and c2.A
pointing to the same address,

Neither one points anywhere. They're not pointers, they're arrays.
They don't store addresses, they store integers.
and changing c1.A means that also c2.A
changes too.

No. They're completely separate objects. Neither c1
nor c2 contains any pointers.

----- BEGIN example CODE -----------

#include <iostream>
using std::cout;
using std::endl;

class C {
private :
int A[3];

public:
C() { for( int i=0; i<3; i++ ) A = 0; };
void alter() { A[1]++; };
void printA() const;
};

void
C::printA() const
{
for( int i=0; i<3; i++ )
cout << "A[" << i
<< "] is " << A
<< endl;
}

int
main( )
{
C c1, c2;

c1.alter();

c2 = c1; // Why does this also make a copy of the array??


It copies the entire contents of the object 'c1' to the
object 'c2'. The previous content of 'c2' is completely
overwritten. The array is part of the contents that's
why it's overwritten.

Since you've not defined your own assignement operator,
this works exactly like assignment for any other type.

cout << " c2 is : " << endl;
c2.printA();

c1.alter();
cout << " c2 is still : " << endl;
c2.printA();

return 0;
}

----- END example CODE -----------

Instead, a copy of the array is made, so touching c1.A doesn't affect
c2.A.

Is this a _c++ standard_ behaviour?

Yes. You wrote the statement which expresses:
"give 'c2' the same value as 'c1'.
If you write your own assignment operator for
class 'C', then you can define a new meaning
for 'assign'.
My lucky guess is that when you
use the default copy constructor,

Do copy ctor is invoked in your code above.
the object at the left of the
assignment gets the memory copied bit-to-bit from the one on the right
side, like a sort of "memcpy()" happens between the two.

Almost.

Not bit by bit, but member by member. This allows for the
cases where some members are of other class types which
might have their own creation and assigment semantics defined.
Copying byte by byte would subvert those operations.
So an array declared as an automatic variable in c1

You're using the wrong terminology. The array 'A' is
a 'nonstatic data member'. It is its containing object,
'c1' that has automatic storage duration. This effectively
gives its members the same duration, but only that of 'c1'.
So if 'c1' were defined as e.g. static, 'A' is certainly
not 'automatic'.

gets its content
copied in the new object (c2) rather than simply the address it's
pointing to,

There are *no* pointers in your code. *Nothing* is being
'pointed to'.
since all the space taken by the array is sequentially
allocated in memory along with other vars declared in the class scope.

Hope my english is understandable enough...

I think understand what you're writing, and I also think
you don't understand about arrays and/or pointers. This
is a big reason why I and others tell beginners to avoid
them and use the standard containers instead. E.g. anything
you can do with an array can be done with a std::vector.

BTW who is teaching you and which book(s) are you studying?

-Mike
 
R

Ron Natalie

Matteo said:
I had been taught that an array isn't a lot different from a pointer

You were taught wrong. You should get a new teacher.
Arrays and pointers are completely different concepts. They
are distinct types. A pointer used to "browse" an array points
at exactly one object within it. The thing that reinforces this
conclusion is an ill-advised conversion from array to pointer to
it's first member that happens.
c2 = c1; // Why does this also make a copy of the array??

Yes, c1 and c2 each have a three element array of int called "A".
The assignment will copy c1.A's elements to c2.A. This is despite
the unfortunate lack of an assignment operator for array types, each
member is copied with it's assignment behavior.

Instead, a copy of the array is made, so touching c1.A doesn't affect
c2

The copy isn't made at the assignment, each object of type C gets the
three element array you declared as soon as it is created.
Is this a _c++ standard_ behaviour? My lucky guess is that when you
use the default copy constructor, the object at the left of the
assignment gets the memory copied bit-to-bit from the one on the right
side, like a sort of "memcpy()" happens between the two.

The copy constructor is NOT used here, what is happening is the implicitly
defined (I prefer to say that rather than default, because default default
cosntructor is confusing) copy-assignment operator performs a member wise
copy on each thing. It's not "sort of memcpy", each member is copied via
it's assignment operator (either implicit or user-defined) and in the case of
the array, each member of the array is copied.
So an array declared as an automatic variable in c1 gets its content
copied in the new object (c2) rather than simply the address it's
pointing to, since all the space taken by the array is sequentially
allocated in memory along with other vars declared in the class scope.

The array is NOT an automatic variable. It is a member variable of the
class. The address isn't copied because it's not a pointer. If it were
a pointer, then the pointers would be assigned. It's an array, so the
array elements are assigned.
 
V

Victor Bazarov

Matteo said:
Ok, I'm quite a newbie, so this question may appear silly. I'm using
g++ 3.3.x.
I had been taught that an array isn't a lot different from a pointer
(in fact you can use the pointer arithmetics to "browse" it). So I
expected that when I run this program, I get both c1.A and c2.A
pointing to the same address, and changing c1.A means that also c2.A
changes too.

----- BEGIN example CODE -----------

#include <iostream>
using std::cout;
using std::endl;

class C {
private :
int A[3];

public:
C() { for( int i=0; i<3; i++ ) A = 0; };
void alter() { A[1]++; };
void printA() const;
};

void
C::printA() const
{
for( int i=0; i<3; i++ )
cout << "A[" << i
<< "] is " << A
<< endl;
}

int
main( )
{
C c1, c2;

c1.alter();

c2 = c1; // Why does this also make a copy of the array??


Because the array is a member. Copy assignment applies assignment
semantics (not necessarily the assignment operator) to all members.
For members that are arrays it means element-wise copy-assignment.
cout << " c2 is : " << endl;
c2.printA();

c1.alter();

You're altering the contents of c1 object.
cout << " c2 is still : " << endl;
c2.printA();

return 0;
}

----- END example CODE -----------

Instead, a copy of the array is made, so touching c1.A doesn't affect
c2.A.

Of course. c1 and c2 are two different objects.
Is this a _c++ standard_ behaviour?

It's the "standard" behaviour of any OO language. Any [non-static] data
members are allocated in the memory set aside for the object that contains
them.
My lucky guess is that when you
use the default copy constructor, the object at the left of the
assignment gets the memory copied bit-to-bit from the one on the right
side, like a sort of "memcpy()" happens between the two.

No, not bit-to-bit. Member-by-member, element-by-element. Members and
elements of arrays are not necessarily 'int'. If they are other class
objects, assignment semantics will mean that operator= is called for them.
So an array declared as an automatic variable in c1

It's not "automatic". It's a _data_member_.
gets its content
copied in the new object (c2) rather than simply the address it's
pointing to, since all the space taken by the array is sequentially
allocated in memory along with other vars declared in the class scope.

Right

V
 
C

Chris Theis

Matteo Settenvini said:
Ok, I'm quite a newbie, so this question may appear silly. I'm using
g++ 3.3.x.
I had been taught that an array isn't a lot different from a pointer
(in fact you can use the pointer arithmetics to "browse" it). So I
expected that when I run this program, I get both c1.A and c2.A
pointing to the same address, and changing c1.A means that also c2.A
changes too.

----- BEGIN example CODE -----------

#include <iostream>
using std::cout;
using std::endl;

class C {
private :
int A[3];

public:
C() { for( int i=0; i<3; i++ ) A = 0; };
void alter() { A[1]++; };
void printA() const;
};

void
C::printA() const
{
for( int i=0; i<3; i++ )
cout << "A[" << i
<< "] is " << A
<< endl;
}

int
main( )
{
C c1, c2;

c1.alter();

c2 = c1; // Why does this also make a copy of the array??

cout << " c2 is : " << endl;
c2.printA();

c1.alter();
cout << " c2 is still : " << endl;
c2.printA();

return 0;
}

----- END example CODE -----------

Instead, a copy of the array is made, so touching c1.A doesn't affect
c2.A.

Is this a _c++ standard_ behaviour? My lucky guess is that when you
use the default copy constructor, the object at the left of the
assignment gets the memory copied bit-to-bit from the one on the right
side, like a sort of "memcpy()" happens between the two.

[SNIP]

Yes, this is standard behavior. If you do not supply a copy constructor,
assignment operator or destructor the compiler implements them for you. Try
to use a dynamically allocated array instead and run your code again. Then
you will see that the bit-wise copy, or assignment respectively, results in
the behavior you expected because not the value pointed to but rather the
pointer is copied or assigned. However, most of the time you would expect a
copy to be a real "copy" and do not want to end up with two different
objects pointing at the same memory. Consequently you have to implement the
copy constructor yourself. Following the "rule of three" you should also go
ahead and implement the destructor and the assignment operator too. If you
need one of the aforementioned you'll most likely need all of them.

HTH
Chris
 
M

Matteo Settenvini

Probably it's me doing just a mess... anyway I'm using a book wrote by
some italians and also "Thinking in C++".

Sorry to appear so "newbieish" but from somewhere you've to start...

But why this isn't legal, then?

----------------

#include<iostream>

int main()
{
int A[10], B[10];
A = B;
}
 
V

Victor Bazarov

Matteo said:
Probably it's me doing just a mess... anyway I'm using a book wrote by
some italians and also "Thinking in C++".

Sorry to appear so "newbieish" but from somewhere you've to start...

But why this isn't legal, then?

----------------

#include<iostream>

int main()
{
int A[10], B[10];
A = B;
}

It's not legal because arrays are not assignable. IOW, an object of
type "array of T" cannot appear on the left side of an assignment op.

V
 
B

Brad Herald

arrays are really pointers to data in memory.

A[10] is a pointer to 10 ints in memory (at least the space is assigned),
contiguous one right after the other.

A = B; // this is trying to assign the B array to the A array, but won't
work unless it's from a class with a copy constructor.

*A = *B; // this will work because it reassigns the A pointer....
/* but this will lead to a memory leak because the array A was
assigned to is now stuck in memory without a way to access the values, the
array is now lost into the memory. if you do want to have two pointers to
the same object, then declare an int* A pointer instead and assign it to B[]
what this leads to is two pointers where either one can change the data
without the other pointer this can be bad because large programs may have
these two pointers and your program may output both at different times
leading to something unexpected since they point to the same data. The best
way to have two arrays is to implement a copy constructor for a class or
simply a copy function if the arrays are not part of a class. */

Brad


Victor Bazarov said:
Matteo said:
Probably it's me doing just a mess... anyway I'm using a book wrote by
some italians and also "Thinking in C++".

Sorry to appear so "newbieish" but from somewhere you've to start...

But why this isn't legal, then?

----------------
#include<iostream>

int main()
{
int A[10], B[10];
A = B;
}

It's not legal because arrays are not assignable. IOW, an object of
type "array of T" cannot appear on the left side of an assignment op.

V
 
M

Matteo Settenvini

Brad Herald said:
arrays are really pointers to data in memory.

oh, well, are they pointers or not? someone tells me they are _really_
pointers, someone that they _aren't_.
A[10] is a pointer to 10 ints in memory (at least the space is assigned),
contiguous one right after the other.
right.


A = B; // this is trying to assign the B array to the A array, but won't
work unless it's from a class with a copy constructor.

*A = *B; // this will work because it reassigns the A pointer....

I thought that this should means:

A[] = { 1, 2, 3 };
B[] = { 4. 5. 6 };

*A = *B;

then you get:

A[] = { 4, 2, 3 };

Obviously, if the two arrays were created with the "new" kw (and thus
int**), what you say makes sense, but that's a different problem.

Anyway, the problem is:
- when I assign directly two pointers I get a compilation error
- when I assign two objects that are of type C, and C is a class that
contains an array as a member, the array is copied and no error is
returned.

is it because I'm creating the class members "ex novo" with a
temporary object when copying them (at runtime?), while both the
arrays in the main() both exist before assignment?
 
V

Victor Bazarov

Matteo said:
oh, well, are they pointers or not? someone tells me they are _really_
pointers, someone that they _aren't_.

Arrays are not pointers. Using the name of an array in an expression
yields a pointer to the first element, yes. That does NOT automatically
make arrays pointers. The act of converting arrays to pointers is often
called "decay", as in "array name decays to a pointer to the first array
element". This conversion is described/defined in subclause 4.2 of the
Standard.
A[10] is a pointer to 10 ints in memory (at least the space is assigned),
contiguous one right after the other.

Nonsense. A[10] by itself is an expression *(A + 10). In a declaration

int A[10];

'A' has type 'an array of 10 ints'. It is NOT a pointer.
right.
Nope.

Nonsense again. A copy constructor has NOTHING to do with this. For
arrays it simply won't work.

In this expression both A and B decay to the pointers to the first
elements of the respective arrays (assuming they are arrays) and the
expression is essentially the same as

A[0] = B[0];
I thought that this should means:

A[] = { 1, 2, 3 };
B[] = { 4. 5. 6 };

The two lines above are not C++.
*A = *B;

then you get:

A[] = { 4, 2, 3 };

I am guessing at this point you're just trying to illustrate what the
values of the elements are, and not writing C++ code. Then, yes.
Obviously, if the two arrays were created with the "new" kw (and thus
int**),
Huh?

what you say makes sense, but that's a different problem.

Anyway, the problem is:
- when I assign directly two pointers I get a compilation error

Huh? Code, please.
- when I assign two objects that are of type C, and C is a class that
contains an array as a member, the array is copied and no error is
returned.

That's correct.
is it because I'm creating the class members "ex novo" with a
temporary object when copying them (at runtime?), while both the
arrays in the main() both exist before assignment?

What?

When an object of a class type is assigned a value of another object of
the same class type, _copy_ assignment operator is invoked. That operator
is a special function. If you don't declare/define one yourself, the
compiler provides it for you. The compiler-provided copy assignment
operator invokes _copying_ for every member. It does NOT invoke operator=
_literally_ for all members, although you could think of it that way. The
data members that are arrays are an exception, essentially. It was done
for backward compatibility with C, where copying is basically bit-by-bit,
because they don't have other copy semantics than that.

If a data member is an array of T, all elements of that array are copied
using their copy semantics. I.e., if they are classes, operator= is used.
If they are built-in classes, internal means are used to copy them.

V
 
J

John Harrison

Matteo Settenvini said:
"Brad Herald" <[email protected]> wrote in message

oh, well, are they pointers or not? someone tells me they are _really_
pointers, someone that they _aren't_.

Brad's post was garbage, arrays are not pointers, they just use similar
syntax. (Mike expressed it well)

All that stuff about memory leaks etc. just garbage.

john
 
A

Arijit

Brad Herald said:
arrays are really pointers to data in memory.

A[10] is a pointer to 10 ints in memory (at least the space is assigned),
contiguous one right after the other.

A = B; // this is trying to assign the B array to the A array, but won't
work unless it's from a class with a copy constructor.

*A = *B; // this will work because it reassigns the A pointer....

No it won't work. This statement will not give a compilation error
like A=B will, but it won't copy B to A either. All it will do is
copy the first element of B to first element of A. The rest of A and B
will remain unchanged.
/* but this will lead to a memory leak because the array A was
assigned to is now stuck in memory without a way to access the values, the
array is now lost into the memory. if you do want to have two pointers to

No memory leak occurs. You can't have a memory leak unless you use
pointers explicitly in your code, or do something fancy with references.
AFAIK, it is impossible to cause memory leaks without using pointers or
references. And arrays are *not* pointers.

-Arijit
the same object, then declare an int* A pointer instead and assign it to B[]
what this leads to is two pointers where either one can change the data
without the other pointer this can be bad because large programs may have
these two pointers and your program may output both at different times
leading to something unexpected since they point to the same data. The best
way to have two arrays is to implement a copy constructor for a class or
simply a copy function if the arrays are not part of a class. */

Brad


Victor Bazarov said:
Matteo said:
Probably it's me doing just a mess... anyway I'm using a book wrote by
some italians and also "Thinking in C++".

Sorry to appear so "newbieish" but from somewhere you've to start...

But why this isn't legal, then?

----------------
#include<iostream>

int main()
{
int A[10], B[10];
A = B;
}

It's not legal because arrays are not assignable. IOW, an object of
type "array of T" cannot appear on the left side of an assignment op.

V
 
A

Arijit

Brad Herald said:
arrays are really pointers to data in memory.

oh, well, are they pointers or not? someone tells me they are _really_
pointers, someone that they _aren't_.
A[10] is a pointer to 10 ints in memory (at least the space is assigned),
contiguous one right after the other.

right.

Wrong. C++ allows A to be interpreted as a pointer to the first element
of the array (AFAIK, for C compatibilty). That does not mean the A is a
pointer. Its an array, which is different from a pointer. Think of it like
this: A[10] as an array only, not a pointer. However, the compiler supplies
an automatic conversion from A to a pointer whenever it is needed.

If you write

int A[10], B[10];

then the type of A is not int* , it is int * const. That is, A is a const
pointer. That is why you can't write A=B; A is const and cannot be assigned to.

A = B; // this is trying to assign the B array to the A array, but won't
work unless it's from a class with a copy constructor.

*A = *B; // this will work because it reassigns the A pointer....

I thought that this should means:

A[] = { 1, 2, 3 };
B[] = { 4. 5. 6 };
*A = *B;

then you get:

A[] = { 4, 2, 3 };

Obviously, if the two arrays were created with the "new" kw (and thus
int**), what you say makes sense, but that's a different problem.

*A = *B will always result in A[] = {4, 2, 3}, whether it is statically
declared or dynamically allocated with new. If the arrays are declared
with new, then A=B is valid. It will merely make A and B point to the
same array and A's memory will be lost. No copying will occur. There
exists no systax in C++(or C) to copy plain arrays.

When you create an array of int with new, the returned pointer is int*,
and not int**. If you create an array of int*, then you get int**.
Anyway, the problem is:
- when I assign directly two pointers I get a compilation error

You should, as I explained earlier. However, if you write int* C = A,
no error will occur because C is not const pointer.
- when I assign two objects that are of type C, and C is a class that
contains an array as a member, the array is copied and no error is
returned.

Because the arrays are part of the class. They are no longer plain arrays.
C++ will do a bitwise copy of member variables of the inbuilt types. So the
arrays, being of type int, gets copied.

-Arijit
 
V

Victor Bazarov

Arijit said:
[...]
If you write

int A[10], B[10];

then the type of A is not int* , it is int * const. That is, A is a const
pointer. That is why you can't write A=B; A is const and cannot be assigned to.

You are just adding to the confusion with this attempt to explain it.
The type of A is "an array of 10 int", not "int * const".

V
 
O

Old Wolf

oh, well, are they pointers or not? someone tells me they are _really_
pointers, someone that they _aren't_.

No they aren't. What "Brad Herald" wrote is utter rubbish
(either a troll, or someone very confused), you should ignore it.
A[10] is a pointer to 10 ints in memory (at least the space is assigned),
contiguous one right after the other.

right.

Wrong, A[10] is an array of 10 ints in memory. it is not a pointer.
&A[0] would be a pointer to a single int (which happens to be
the first int in an array). &A would be a pointer to an array of
10 ints.

C has a (confusing) rule that if you write 'A' in
most expressions, and A is an array, it silently treats it as
&A[0], ie. a pointer to the first element of the array. This is
why you can use the same syntax for arrays as for pointers.

Wrong. according to the rule I just mentioned, A = B gets treated
as: &A[0] = &B[0], which is obviously not going to work.

This is the same whether or not it is in a copy constructor.
*A = *B; // this will work because it reassigns the A pointer....

I thought that this should means:

A[] = { 1, 2, 3 };
B[] = { 4. 5. 6 };
*A = *B;
then you get:
A[] = { 4, 2, 3 };

Yes that's right
Obviously, if the two arrays were created with the "new" kw (and thus
int**), what you say makes sense, but that's a different problem.

The new keyword returns a pointer. So it is a different problem,
as you say. What he said about *A = *B is still wrong though.
Anyway, the problem is:
- when I assign directly two pointers I get a compilation error

No you don't. ITYM that you get a compilation error when
you assign two arrays (which is correct).
- when I assign two objects that are of type C, and C is a class that
contains an array as a member, the array is copied and no error is
returned.

Yes, this is a feature of structs that when they get assigned,
array members get copied by value properly. This feature wasn't in
early drafts of C, which did not allow structs to be assigned,
but was added for 1989 ANSI C. Unfortunately they did not
also decide to allow assignment for standalone arrays.
is it because I'm creating the class members "ex novo" with a
temporary object when copying them (at runtime?), while both the
arrays in the main() both exist before assignment?

No it is nothing to do with anything like that.
 
B

Brad Herald

Course webpage (http://courses.cs.vt.edu/~cs1704/fall03/)

I know this instructor who put this together agrees concisely with other
professors as to the validity of the notes below. I know he has programmed
in C++ for many years as well as his colleagues. I learned a lot of C++
from this instructor.

Perhaps if Mr. Stroustrup were to visit and correct a misperception about
arrays and pointers.



Anyway, an excerpt (below) is from the course notes at the following link.

http://courses.cs.vt.edu/~cs1704/fall03/Notes/C03.Pointers.pdf

Pointer Expressions

Arrays == Pointers

- Non-indexed Array variables are considered pointers in C

- Array names as pointers contain the address of the zero

element (termed the base address of the array).

Given:

Pointer Indexing

- All pointers can be indexed,

(logically meaningful only if the pointer references an array).

- Example:

Logical Expressions

- NULL tests:

- Equivalence Tests:

const int size = 20;

char name[size];

char *person;

person = name;

person = &name[0];

equivalent assignments

person[0] = ' ';

person[size-2] = '.';

if (!person) //true if (person == NULL)

preferred check

if (person == name)

//true if pointers reference

//the same memory address

pointer types

must be

identical
 
B

Brad Herald

a memory leak occurs when? dynamically allocated space assigned to a
pointer and it isn't deleted before the pointer goes out of scope. If we
wanted to get into the heavy dynamic stuff, I'm game.

int* first = new int(20);
int* second = new int(10);

first = second; // memory leak, the memory is allocated in the heap and
'first' is no longer pointing to it's allocation
//add before the previous line, 'delete [] first;' and then define first
again, int* first = second;
-------------------------------
(using the above declarations)
int length = sizeof(int);
int i=0;
for( i=0; i < 10; i++ )
cout << *(first + i*length); // regardless of what values are in the
memory space, it'll be output

----------------------
(using the above declarations)
int i=0;

for( i=0; i < 10; i++ )
cout << first;

--------------------------
The second two examples do the exact same thing.


I was trying to bring out the carefullness required when assigning two
pointers:
1) know what each one points to
2) know if the pointer's destination is static or dynamic
3) if the pointer to be assigned points to something dynamic, delete the
contents or else instantiate another pointer
---------------------------
A linked list is much like an array, except it is not contiguous. The nodes
are scattered throughout memory, but each node (in a working list) has at
least one pointer to the next node and possibly (double linked list) another
pointer to the node which points to it. All of this is for internal nodes
and the first node's previous pointer points to NULL and the last node's
next pointer points to NULL. Unless it is a circular list, that is if you
were to give the command to print out the node's contents and the next in
line without checking for the root of the list, then you get an infinite
loop.

I've written my own linked list (and templated it) and used it in many
programs.
-----------------------------
Lastly, what is an array exactly? Is an array a C++ type?
Take a look at C++ abstract declarators in any good C++ book.

"Arrays are derived types and can therefore be constructed from any other
derived or fundamental type except functions, references, and void." VS.NET
C++ Reference

----------------------------
Arijit said:
Brad Herald said:
arrays are really pointers to data in memory.

A[10] is a pointer to 10 ints in memory (at least the space is assigned),
contiguous one right after the other.

A = B; // this is trying to assign the B array to the A array, but won't
work unless it's from a class with a copy constructor.

*A = *B; // this will work because it reassigns the A pointer....

No it won't work. This statement will not give a compilation error
like A=B will, but it won't copy B to A either. All it will do is
copy the first element of B to first element of A. The rest of A and B
will remain unchanged.
/* but this will lead to a memory leak because the array A
was
assigned to is now stuck in memory without a way to access the values,
the
array is now lost into the memory. if you do want to have two pointers
to

No memory leak occurs. You can't have a memory leak unless you use
pointers explicitly in your code, or do something fancy with references.
AFAIK, it is impossible to cause memory leaks without using pointers or
references. And arrays are *not* pointers.

-Arijit
the same object, then declare an int* A pointer instead and assign it to
B[]
what this leads to is two pointers where either one can change the data
without the other pointer this can be bad because large programs may have
these two pointers and your program may output both at different times
leading to something unexpected since they point to the same data. The
best
way to have two arrays is to implement a copy constructor for a class or
simply a copy function if the arrays are not part of a class. */

Brad


Victor Bazarov said:
Matteo Settenvini wrote:
Probably it's me doing just a mess... anyway I'm using a book wrote by
some italians and also "Thinking in C++".

Sorry to appear so "newbieish" but from somewhere you've to start...

But why this isn't legal, then?

----------------
#include<iostream>

int main()
{
int A[10], B[10];
A = B;
}

It's not legal because arrays are not assignable. IOW, an object of
type "array of T" cannot appear on the left side of an assignment op.

V
 
V

Victor Bazarov

Brad said:
a memory leak occurs when? dynamically allocated space assigned to a
pointer and it isn't deleted before the pointer goes out of scope. If we
wanted to get into the heavy dynamic stuff, I'm game.

int* first = new int(20);
int* second = new int(10);

Both lines allocate _one_ int exactly. Each. '*first' is initialised
with the value 20, '*second' with the value 10.
first = second; // memory leak, the memory is allocated in the heap and
'first' is no longer pointing to it's allocation
Yes.

//add before the previous line, 'delete [] first;' and then define first
again, int* first = second;

This is wrong. You only 'delete[]' what is allocated using new[]. You
must define an object only once. So, the memory leak is cured if you do

delete first;
first = second;
-------------------------------
(using the above declarations)
int length = sizeof(int);
int i=0;
for( i=0; i < 10; i++ )
cout << *(first + i*length); // regardless of what values are in the
memory space, it'll be output

This is another example of wrong things. 'first' points to a single int
in the free store. Attempting to dereference (first+<non-zero value>)
will cause undefined behaviour. That's one. Second, since 'first' has
type "a pointer to int", there is no need to multiply 'i' with sizeof(int)
to get to the i-th int. Where did you get that nonsense?
----------------------
(using the above declarations)
int i=0;

for( i=0; i < 10; i++ )
cout << first;


Same here. Only if 'i' equals 0, the output is OK.

No, they don't.
I was trying to bring out the carefullness required when assigning two
pointers:
1) know what each one points to
2) know if the pointer's destination is static or dynamic
3) if the pointer to be assigned points to something dynamic, delete the
contents or else instantiate another pointer

Those are good recommendations, you just need to work on your delivery
to avoid people slamming you against your will.
---------------------------
A linked list is [..irrelevant bragging removed..].
-----------------------------
Lastly, what is an array exactly? Is an array a C++ type?
Yes.

Take a look at C++ abstract declarators in any good C++ book.

Take a loot at the Standard.
"Arrays are derived types and can therefore be constructed from any other
derived or fundamental type except functions, references, and void." VS.NET
C++ Reference

So? Pointers, references, are also "derived types". What's your point?

And, finally, try not to top-post, will you?

V
 
B

Brad Herald

Victor Bazarov said:
Brad said:
a memory leak occurs when? dynamically allocated space assigned to a
pointer and it isn't deleted before the pointer goes out of scope. If we
wanted to get into the heavy dynamic stuff, I'm game.

int* first = new int(20);
int* second = new int(10);

Both lines allocate _one_ int exactly. Each. '*first' is initialised
with the value 20, '*second' with the value 10.
first = second; // memory leak, the memory is allocated in the heap and
'first' is no longer pointing to it's allocation
Yes.

//add before the previous line, 'delete [] first;' and then define first
again, int* first = second;

This is wrong. You only 'delete[]' what is allocated using new[]. You
must define an object only once. So, the memory leak is cured if you do

delete first;
first = second;

being a few years out from consistent programming, I would've chosen int[20]
instead of int(20). Then the brackets are necessary in delete. And then,
'int* first' later was wrong because even though first was deleted, the
instance is still defined pointing to nowhere, so hence it can be reassigned
to something else or left to wash out after the program.
This is another example of wrong things. 'first' points to a single int
in the free store. Attempting to dereference (first+<non-zero value>)
will cause undefined behaviour. That's one. Second, since 'first' has
type "a pointer to int", there is no need to multiply 'i' with sizeof(int)
to get to the i-th int. Where did you get that nonsense?

Pointer arithmetic. The compiler won't check (some do) if the user attempts
to access a static array outside the bounds. An error will crop up during
run-time. Anyway, a pointer (can be) is a reference to the beginning of
some data. Someone can write in pointer arithmetic as an offset from the
base and access the elements after knowing the space between each different
element if they were using a void*.
----------------------
(using the above declarations)
int i=0;

for( i=0; i < 10; i++ )
cout << first;


Same here. Only if 'i' equals 0, the output is OK.

No, they don't.


If the two were set up correctly, they could do the same thing. I
mistakenly tried to recall what I remembered doing 2-3 years ago without
trying it. It is possible to use the [ ] operator and the * operator to
accomplish the same task, of which I failed to clearly illustrate.


Perhaps it was improper to directly relate arrays to being solely pointers,
though the data stored in an array resides at address in contiguous space
and has a pointer to the first element, int A[10], which would be &A[0].

(illustratively)
A[0] A[1] A[2]
A[10] = 5, 15, 25 ...
| | | |
*A *(A+1) *(A+1) *(A+2) ...

For not being pointers, arrays can be handled as pointers somewhat nicely.
Those are good recommendations, you just need to work on your delivery
to avoid people slamming you against your will.

It is so hard to know people's experiences when posting to a news group.
You apparently have had plenty of work in C++ to know the deeper
intricacies. There also appears to be many different experiences on here
from novice C++ to veteran C++ and veteran <fill in the language but novice
C++>. So how can anyone help to generalize a concept without confusing them
and making them hate C++ because it seems hard? I try to make an 'in the
end' kind of statement to let the novice user understand without all the
details. If I have to, I want to explain the details following to explain
why I came to such a conclusion.
So? Pointers, references, are also "derived types". What's your point?

I hope you meant 'derived types' in a different way. Since we are being
specific, pointers and references aren't truely derived. They represent
memory addresses in a high level language.
 
V

Victor Bazarov

Brad Herald said:
Victor Bazarov said:
Brad said:
a memory leak occurs when? dynamically allocated space assigned to a
pointer and it isn't deleted before the pointer goes out of scope. If
we wanted to get into the heavy dynamic stuff, I'm game.

int* first = new int(20);
int* second = new int(10);

Both lines allocate _one_ int exactly. Each. '*first' is initialised
with the value 20, '*second' with the value 10.
first = second; // memory leak, the memory is allocated in the heap and
'first' is no longer pointing to it's allocation
Yes.

//add before the previous line, 'delete [] first;' and then define
first again, int* first = second;

This is wrong. You only 'delete[]' what is allocated using new[]. You
must define an object only once. So, the memory leak is cured if you do

delete first;
first = second;

being a few years out from consistent programming,

No offence, but perhaps you should then consider getting back in shape
before thinking of dispensing advice. I am not trying to discourage you
from participating here, don't get me wrong. I am simply trying to help
you avoid losing too much hair.
I would've chosen int[20] instead of int(20). Then the brackets are
necessary in delete. And then, 'int* first' later was wrong because even
though first was deleted, the instance is still defined pointing to
nowhere, so hence it can be reassigned to something else or left to wash
out after the program.
This is another example of wrong things. 'first' points to a single int
in the free store. Attempting to dereference (first+<non-zero value>)
will cause undefined behaviour. That's one. Second, since 'first' has
type "a pointer to int", there is no need to multiply 'i' with
sizeof(int)
to get to the i-th int. Where did you get that nonsense?

Pointer arithmetic. The compiler won't check (some do) if the user
attempts to access a static array outside the bounds. An error will crop
up during run-time. Anyway, a pointer (can be) is a reference to the
beginning of some data. Someone can write in pointer arithmetic as an
offset from the base and access the elements after knowing the space
between each different element if they were using a void*.

What's all this? Pointer arithmetic behaves dependent on the type of the
pointed object. Your i*length is _wrong_ if you intended to reach each
of the 10 allegedly allocated elements of the dynamic array to which 'first'
pointed. Bounds or no bounds, what you did is stepping _over_ four ints
at a time (if sizeof(int)==4) instead of getting every element.
----------------------
(using the above declarations)
int i=0;

for( i=0; i < 10; i++ )
cout << first;


Same here. Only if 'i' equals 0, the output is OK.

No, they don't.


If the two were set up correctly, they could do the same thing.


"Set up correctly"? "Could"?

For any type T, if 'p' has type 'T*' (a pointer to T), the expression

p

is equivalent to

*(p + i)

and NOT to

*(p + i*sizeof(T))

So, the two loops are not going to do the same thing since they use
different indexing. The only time where they _accidentally_ might
do the same thing is if 'T' were one of the three 'char' types, and
only because 'sizeof' in that case is 1.
I mistakenly tried to recall what I remembered doing 2-3 years ago
without trying it. It is possible to use the [ ] operator and the *
operator to accomplish the same task, of which I failed to clearly
illustrate.
Yes.

Perhaps it was improper to directly relate arrays to being solely
pointers,

Yes, it was.
though the data stored in an array resides at address in contiguous space
and has a pointer to the first element, int A[10], which would be &A[0].

(illustratively)
A[0] A[1] A[2]
A[10] = 5, 15, 25 ...
| | | |
*A *(A+1) *(A+1) *(A+2) ...

I think something is lost here due to reformatting in some news posting
software. Generally speaking, you didn't have to go into memory layout to
say that for pointers p is the same as *(p+i). Incidentally, you may
write i[p] and it will work because you may swap the operands of the +
and have the same result (for built-in types, that is).
For not being pointers, arrays can be handled as pointers somewhat nicely.

They are converted to pointers where necessary.
It is so hard to know people's experiences when posting to a news group.

The main thing here is to know your own capabilities, not to try guessing
other's. Try not to jump in with giving recommendations. Lurk around and
read for some time before you feel that your level allows you to help
others.

If you have other things to do, it's not that difficult to let some of the
postings be answered by others. It doesn't necessarily mean that you gave
up or don't know the answer, you know.
[..]So how can anyone help to generalize a concept without confusing them
and making them hate C++ because it seems hard?

I am not sure what you mean here.

It is possible to kill a starving person by giving them too much food at
once. It is possible to confuse a person in need of advice by giving too
much information. Especially incorrect information.
I try to make an 'in the end' kind of statement to let the novice user
understand without all the details.

Actually, as soon as you start talking addresses and how things lie in
memory, you do go into "all the details", which the novice doesn't really
need.
If I have to, I want to explain the details following to explain why I
came to such a conclusion.

Take a break from explaining for a couple of days. Catch your breath.
Look around. Evaluate the environment, see what you can get out of it and
what you can give back to it. Sometimes you can learn more by simply
listening than by talking and being corrected. Although if one's mistakes
are not being corrected, one would never know that they were mistakes...

Visit alt.comp.lang.learn.c-c++. Not for the purpose of teaching those
who ask questions there but for the same purpose as here, see what folks
ask, what asnwers they're given. See if you can participate without doing
too much damage, mostly to your reputation.
I hope you meant 'derived types' in a different way. Since we are being
specific, pointers and references aren't truely derived. They represent
memory addresses in a high level language.

By "derived" I mean that they don't exist by themselves. Every pointer to T
needs 'T' to be something concrete before you can use it. Every reference
to
T will only be defined when 'T' is defined. That makes them dependent, or
"derived", or, as the Standard calls them, "compound". Whether it differs
from your meaning of "derived", I don't know. You didn't state what you
meant under "derived". You don't have to answer if you don't want to.

Good luck!

V
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top