I have a small C++ program defined below:
class Test
{
public:
int a;
int b[a];
};
When compiling, it produces an error:
testClass.C:7:5: error: invalid use of non-static data member ‘Test::a’
testClass.C:8:7: error: from this location
testClass.C:8:8: error: array bound is not an integer constant before ‘]’ token
How do I learn about what the error message means, and how do I fix it?
You cannot use an array with undefined size in compile time. There are two ways: define a as static const int a = 100; and forget about dynamic size or use std::vector, which is safer than the manual memory management:
class Test
{
public:
Test(int Num)
: a(Num)
, b(Num) // Here Num items are allocated
{
}
int a;
std::vector<int> b;
};
Unless you dynamically allocate them (such as with new[]), arrays in C++ must have a compile-time constant as a size. And Test::a is not a compile-time constant; it's a member variable.
Let's go through the complete reason behind this, first of all when you declare a class initially, any member variable has not been allocated any memory, so public or private methods have no value. That was a quick tip for you, now for your problem:
You can't do that outside the class since any array size should be known before the compilation because any statically declared array resides in the function's stack frame, and the compiler needs to know how much memory to allocate exactly. The only segment in memory that is resized by the programmer is the heap. So, whenever you want to have a dynamically allocated array size, you need to declare it to reside in the heap, and you do that like so:
int a;
cin >> a;
int * b = new int[a];
That's the correct way to declare an array with an unknown size (size determined during the runtime), to integrate this with your class here is how you do it, and recall that any class private or public attributes have no memory - They are just declarations that should not contain any initialization somewhere else in the member methods or outside the class - this is because they are public, as in your case - and of course after declaring an instance of the class e.g Test t. Anyway, here is how you do it within the class:
class Test
{
public:
int a;
int * b;
Test(int Ia=1) {
a = Ia;
b = new int[a];
}
~Test() {
delete[] b;
}
};
See delete vs delete[] operators in C++ for why to use delete[] instead of delete in the destructor.
Related
Given the following code:
class MyClass
{
public:
char array[10];
};
int main()
{
MyClass *p = new MyClass;
...
}
As far as I understand - new allocates the object on the heap.
But also, the array is allocated on the stack (no new operator).
So, is the array allocated on heap (because the object is at the heap) or on the program stack?
But also, the array is allocated on the stack (no new operator)
No, the array is a member of the object. It's a part of it. If the object is dynamically allocated, then all of its parts are too.
Note I said all of its parts. We can tweak your example:
class MyClass
{
public:
char *p_array;
};
int main()
{
char array[10];
MyClass *p = new MyClass{array};
// Other code
}
Now the object contains a pointer. The pointer, being a member of the object, is dynamically allocated. But the address it holds, is to an object with automatic storage duration (the array).
Now, however, the array is no longer part of the object. That disassociation is what makes the layout you had in mind possible.
What MyClass *p = new MyClass; really means is that you want to allocate sizeof(MyClass) bytes on the heap/free store to store every member of MyClass. The size of a class is based on it's members. array is a member of MyClass and thus because MyClass is allocated on the free store, so is array.
What happens if a class instantiates all it's local variables on the stack (ie: int i; //An integer on stack versus int *p; //Pointer to an int) while the class itself is instantiated on the heap? Where are the class members?
Here's an example:
class A {
public:
int a, b; //These are instantiated on the stack, if the line were written outside a class definition.
A(int _a, int _b) {
a = _a;
b = _b;
}
};
Now, if we instantiate A like this:
#include <iostream>
A* classA = new A(1,2);
int main(void) {
std::cout << classA.a << "\t" << classA.b << endl;
return 0;
}
Where are classA.a and classA.b? Are they on the program stack? Are the automatically put on the heap instead, as classA is?
Not a problem in most cases, I wouldn't think, but it might be helpful to know...
int a, b; //These are instantiated on the stack,
No, these are not instantiated on the stack. Member variables are parts of the instance data structure, and thus are allocated in the same memory chunk as the class instance. Only if the class instance is on the stack, then the instance fields are there as well.
This line is factually incorrect
int a, b; //These are instantiated on the stack, normally
It depends on how the object is created - using new or on the stack
A class is a definition of a data structure; a block of memory. It does not define where that block of memory comes from. However, all the memory for a single object comes from the same place.
static Class A ;
Allocates all the data for A in a stack program section.
. . . . .
{
Class A ;
}
Allocates ALL the data for A on the stack (or whatever mechanism used---the stack).
Class *A = new A ;
Allocates all the data for A in dynamic memory.
I would like to define a class with a vector data member. The class looks as follows
class A{
...
private:
std::vector<int> v1;
...
};
If I use operator new to allocate memory for class A, the program is OK. However, if I get the memory from the pre-allocated memory and cast the pointer to type A*, the program will crash.
A* a = new A;
A* b = (A*)pre_allocated_memory_pointer.
I need one vector with variable size and hope to get the memory for A from one pre-allocated memory. Do you have any idea about the problem?
An std::vector is an object that requires initialization, you cannot just allocate memory and pretend you've got a vector.
If you need to control where to get the memory from the solution is defining operator::new for your class.
struct MyClass {
std::vector<int> x;
... other stuff ...
void *operator new(size_t sz) {
... get somewhere sz bytes and return a pointer to them ...
}
void operator delete(void *p) {
... the memory is now free ...
}
};
Another option is instead to specify where to allocate the object using placement new:
struct MyClass {
std::vector<int> x;
... other stuff ...
};
void foo() {
void * p = ... get enough memory for sizeof(MyClass) ...
MyClass *mcp = new (p) MyClass();
... later ...
mcp->~MyClass(); // Call destructor
... the memory now can be reused ...
}
Note however that std::vector manages itself the memory for the contained elements and therefore you'll need to use stl "allocators" if you want to control where the memory it needs is coming from.
It is not enough to cast the pre-allocated memory poiner to your user-defined type unless this UDT is "trivial".
Instead, you may want to use the placement new expression to actually call the constructor of your type at the provided region of memory:
A* b = new(pre_allocated_memory_pointer) A();
Of course, you need to ensure that your memory is properly aligned and can fit the whole object (i.e. its size is >= sizeof(A) ) beforehand.
Don't also forget to explicitly call the destructor for this object before de-allocating the underlying memory.
b.~A();
deallocate(pre_allocated_memory_pointer);
As I understand your question you are confusing the data memory of the std::vector with the memory it takes up as a member.
If you convert pre_allocated_memory_pointer to A*, then no constructor got called and you have an invalid object there. This means that the v1 member will not have been constructed and hence no memory has been allocated for the vector.
You could use placement new to construct the A instance at the pre_allocated_memory_pointer position but I doubt that is what you want.
In my opinion you want a custom allocator for the vector that gets the memory for the vector's data from the preallocated memory pool.
I am receiving "Segmentation fault" when I try to populate my array. So I was think of declaring the arrays size in the class to declare the array's size so it can allocate the space, but I receive.
error: invalid use of non-static data member ‘Array::Size’ error: from
this location
//Current
class Array{
public:
int Size;
int Range;
int Array[];
};
//Problematic
class Array{
public:
int Size;
int Range;
int Array[Size];
};
or there any other method of preventing an Segmentation fault?
You're attempting to use a C idiom, where the last member of a structure is a very short array (one or, if permitted by the compiler as a nonstandard extension, zero elements) and extra memory is allocated for the structure so elements beyond the end of the declared array can be accessed. This was originally a nonstandard trick, known as the struct hack, or in some compilers as zero-length arrays. It was standardized in C99 as flexible arrays.
When you used this idiom, you needed to allocate additional memory for the array, e.g. sizeof (struct Array) + sizeof (int) * number_of_elements. Otherwise you wouldn't have memory allocated for more elements than you actually declared (usually one or zero), and you'd get undefined behaviour when you tried to access elements beyond that.
However, you're writing C++, not C99. Even if your compiler allows you to do this, relying on it would be very bad practice, and a lot more awkward C++ than in C.
Either store a pointer in the class and allocate the appropriate amount of memory in the constructor, and deallocate it in the destructor, or use a C++ class that will manage the memory for you, e.g. std::vector.
Here's an example of using std::vector:
#include <vector>
class Array{
public:
int size;
int range;
std::vector<int> array;
Array(int size, int range) :
size( size ),
range( range ),
array( size, 0 )
{
}
};
Both these definitions
//Current
class Array{
public:
int Size;
int Range;
int Array[];
};
//Problematic
class Array{
public:
int Size;
int Range;
int Array[Size];
};
are invalid. The first one is invalid because class definition may not containg incomplete non-static data members. You may not write int Array[];
The second one is invalid because 1) data member Size has undefined value and 2) the size of an array shall be a constant expression.
Instead of declaring array you could use a pointer and dynamically allocate an array of the required size.
You can use pointer.
class Array{
public:
int Size;
int Range;
int* Array;
};
In the constructor, you can allocate memory for it. Or maybe you can do it in a member function.
Array::Array(/*parameters*/){
/* code */
Array = new int [Size] //After Size is initialized or assigned.
}
In the destructor, you should use delete[] Array to deallocate the memory.
What happens in the following code?
I guess it doesn't work since I get a segmentation fault if I want to add something to the b array, but what exactly did I do here?
Is there no way of specifying the size of an array inside the constructor?
class A {
public:
A() {
b[3];
}
private:
B b[];
};
B b[] here is a "flexible array member", a non-standard extension in your compiler (taken from C99) that allows you to declare an unbounded array as the last member in a type. It's only of use when allocating your object the old-fashioned C way (when you pad your argument to malloc to make space for the array), and ought to be avoided. In this case, you haven't allocated any extra memory for the array, so in your constructor body when you're trying to access something that occurs 3 'elements' past this nothingness, you're invoking UB. I'll ignore the extension for the rest of my answer, as it really has no place in C++ code.
Is there no way of specifying the size of an array inside the constructor?
No, there isn't.
Array bounds must be known at compile-time, so there is no case where you know more in your ctor body than you do in the class definition; you are required to write the dimension in the member's declaration itself:
class A {
B b[3];
};
If the dimension is a run-time quantity in your program, you'll need to instead store a pointer and, in your constructor, point it at a dynamic block of memory:
class A {
public:
A() : b(new B[3]) {}
~A() { delete[] b; }
private:
B* b; // same as `B b[]`! but far clearer
};
Instead, though, I suggest a std::vector:
class A {
public:
A() : b(3) {}
private:
std::vector<B> b;
};
Yes. Using operator new: b = new B[3];. Declare b as B *b for that.
Of course, you need to delete[] it in the destructor.
But a better way would be using std::vector instead of the array, and then you don't need to worry about preallocating memory.
C++ doesn't support any types with size determined at runtime. Therefore you have only the options to determine the array size at compile time (possible through a non-type template parameter) or move the array out of the object by making b a pointer and allocating memory for it with new (or, better, let the standard library do that for you by using a vector).
This is not possible - what would you expect sizeof(A) to evaluate to?! If you really need such functionality, use dynamic allocation, i.e. a private member variable B *b, b(new B[3]) in the constructors initializer list, and delete[] b; in the destructor.