This question is about C++
I always thought that name of an array in C++ is only a pointer, so I thought that
int ar[10];
cout << sizeof(ar);
will give me the same as sizeof(int *)
. But it gives 40 - so it is real size of whole array. It also gives 40 when array size is given by variable:
int n = 10;
int ar[n]
I want to copy a class that contains an array. If it would be allocated with operator new
then I should manualy copy this array within a copy constructor. But how about constant sized arrays? Does class contains only a pointer to an array, or does it contains whole array? Is simple memcpy(...)
safe here?
EDIT: Another example:
int n;
cin >> n;
int ar[n];
cout << sizeof(ar);
and it prints n*4. I'm using g++ on linux.
I even tried this:
class Test {
public:
int ar[4];
};
and
Test a, b, c;
a.开发者_Python百科ar[0] = 10;
b = a;
memcpy(&c, &a, sizeof(a));
a.ar[0] = 20;
cout << "A: " << a.ar[0] << endl;
cout << "B: " << b.ar[0] << endl;
cout << "C: " << c.ar[0] << endl;
and it gives:
A: 20
B: 10
C: 10
So array is stored as a part of a class and can be copied with memcpy. But is it safe?
An array is not a pointer. The name of an array "decays" to a pointer when/if you pass it as a parameter to a function -- but sizeof
is an operator built into the language, not a function, so sizeof(array)
yields the actual size of the array as long as it's applied to the actual array (as opposed to the name of the array being passed as a parameter, then using sizeof()
on the pointer that it decayed to when it was passed to the function.
As far as copying a class that contains an array, if it's really an array, like:
class X {
int x[10];
};
Then you don't need to do anything for it to be copied -- the compiler can/will generate a copy constructor that copies the contents of the array. If (and only if) you actually have a pointer, and allocate the space yourself, do you need to write a copy ctor to do a "deep copy" (i.e. allocate space in the new object, and copy the data pointed TO by the pointer). Rather than doing this, however, you should normally use an std::vector
, which does all that internally so you don't have to worry about it.
Taking these one at a time:
I want to copy a class that contains an array.
Okay, so for example:
class Foo
{
int arr[20];
};
If it would be allocated with operator new then I should manualy copy this array within a copy constructor.
Okay, now the confusion sets in. In the above example, the array is actually part of the object. sizeof(Foo)
would give you 80 if int
is 4 bytes.
An alternative would be to have a pointer to an array, which is useful if the array needs to change size:
class Bar
{
int *arr;
};
In that case, sizeof(Bar)
is the size of a pointer (usually 4 or 8 bytes), and copying the object copies the pointer. This is called a "shallow copy". If you wanted a "deep copy", i.e. a copy would duplicate the array's contents and not just the object, then you need a copy constructor.
The third alternative is to use vector
, as wheaties recommends:
class Bob
{
std::vector<int> arr;
};
This internally works the same as the Bar
case, and the vector
can be resized, but the vector
template takes care of the deep copy for you, so you don't need a copy constructor.
I'd recommend the Foo
case if you need a fixed-size array, where the size is known at compile time, and the Bob
case otherwise. The Bar
case is pretty much just reinventing the wheel.
Is simple memcpy(...) safe here?
Safe for Foo
. Safe for Bar
if you want a shallow copy. Unsafe for Bob
.
The moral of the story is that storing a variable in an object works just like storing it in a function block or global: if you specify an array ([N]
instead of *
), the size had better be determined at compile time, and you get the storage placed right there.
Actually ar
is an array, that is why sizeof() finds the actual size. An array in C/C++ has a pointer value (pointer expression or rvalue).
int ar[10];
int *p;
p = ar; // OK
ar = p; // error
Comment : in standard C (C89) you should only be able to initialize an array with a literal or a const. So there is no confusion for the compiler.
Answer : If you initialize an array in the "on the stack way" -- i.e., without using new or malloc. The class would encapsulate the size of the array. The base of an array is a pointer because the compiler uses pointer arithmetic internally to resolve the access operator []
.
If you use new or malloc, then you must use variable that you used to allocate memory as the definitive measure of the size of the memory you allocated. you may use memcpy()
with the array base pointer, as irrespective of where it is allocated, it is still a pointer to the base memory location of the array.
answer 2: after question edits
Yes it is perfectly safe to do that with const-sized arrays of the same type and of the same size, but do not do it with dynamically allocated resources unless you are tracking their types and sizes. Just avoid the approach you are taking and go with a container class.
Note : I have evaded your point on the sizeof
operator on heap allocated memory as I cannot say what the behaviour is. I am old-school and I would never use sizeof on dynamic resources as it depends on runtime machinery, and who knows what runtime machinery different compiler vendors include.
However, I know this, that when an array is alloced by new (on most compilers) in C++ it places a integer -- physically -- at the base of the array. This integer represents the size of the array that follows. This is why you must use the delete []
operator, this operator differs from standard delete
because it causes the compiler to spit out a loop which itteratively calls the destructor on your items. If a C++ compiler vendor place an integer at the base of an array than they might use this at runtime to extract it for the sizeof operator. I have no idea what the standard says about it, and I doubt it works this way.
TEST: Visual Studio 2008
#include "stdafx.h"
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
int x;
int *y=new int[5];
int z[5];
std::cout << sizeof(x);
std::cout << " " << sizeof(y);
std::cout << " " << sizeof(z);
return 0;
}
OUTPUT:
4 4 20
You can only determine the size of an array at runtime if its hard-coded -- i.e., like in the case of z. x is an int and y is a pointer both behave as such.
Have you looked into STL's vector. That behaves similar to an array, has adjustable size, and contains a function "size()" which returns the size of the array.
sizeof(ar)
only works because the declaration of ar
is visible to the compiler at that point.
Array sizes are not stored and never available in runtime, if you pass ar
to a function and do sizeof(ar)
there you'll get 4
. So its basically that your compiler is smart enough to look a couple of lines above.
sizeof
is a compiler keyword that will deliver a size in compile time. So the compiler must be able to know, or deduce, the size of the var you are looking at to give the proper size.
REEDIT: : sizeof
is a compile-time constant [except for C99 variable-length arrays] where the compiler can add runtime computation. This however is a compiler extension to C++ as C99 is not part of the C++ standard.
精彩评论