Array in Constructor - c++

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.

Related

A reference to the object of the class with dynamically allocated memory and destructor

Let's assume I have three classes:
class A{
};
class B{
int S;
A* arr;
B(int s):S(s){
arr = new A[S];
}
~B(){
delete [] arr;
}
};
class C{
B& b;
C(B& b): b(b){}
};
Should I define explicitly a destructor in class C? What would it look like?
Should I define explicitly a destructor in class C?
To answer that question, you must know what your class does. Is the purpose of the class to manage allocated memory? Then, yes you probably need a destructor. Is the purpose to refer to an object managed by something else? Then why would you need a destructor? If you don't know what a destructor should do, then you quite often do not need one.
You should never use owning references, so there should be little reason for C to have a destructor, or it has to be changed drastically.
You also should not use owning bare pointers, so class B should also be changed. Easiest solution is to replace it with std::vector.
No, you don't need a destructor for C, but you do need a copy-constructor (as well as a move-constructor, copy-assignment operator and move-assignment operator) for class B if you want to correctly implement copy-semantics. As it is now if you were to make a copy of an object of class B, you would have to objects pointing to the same array - when the objects are destructed you would get a double delete causing undefined behavior.
You don't need to use a raw pointer. You can simply use a std::vector will handle the allocation of the elements as well as its destruction. That also means that you won't need to implement any other kinds of constructors or a destructor for B since std::vector handles copies and moves correctly.

One class with a vector data member

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.

use stl map as member of struct

I'm constructing a struct with one of the member being a map.
First question is this allowed? The compiler did not complain.
struct A {
map<int, float> B;
}
Later I declare an array of such data type.
A *C = (A *)INTERNAL_CALLOC(..., sizeof(A));
Here the function INTERNAL_CALLOC is a functional wrapper of MALLOC.
Later on in the code when I try to first time insert an item into the array's first element's map, I got a core dump.
C[0].B[0] = 0.001;
Any idea why is this the case?
Thanks!
Yes, a map in a struct is fine.
Allocating with malloc is definitely not fine; the constructor is not called. So your map will most likely do something terrible when you attempt to use it.
General rule of thumb: don't use malloc/calloc/realloc/free in C++. Avoid dynamic allocation wherever possible, and use new/delete when unavoidable.*
* And read up on smart pointers.
If you really must allocate with INTERNAL_CALLOC, then use placement new.
First, you must define a constructor and a destructor for the type A, or define A as a class:
struct A {
A(){}
~A(){}
map<int, float> B;
};
Then you can simply call:
//Allocate an A, uninitialized
A *C = (A *)INTERNAL_CALLOC(..., sizeof(A));
//Initialize the newly allocated A
new (C) A();
later when you free the object you must explicitly call the destructor:
//A *C;
C->~A();
INTERNAL_free(C);
A *C = (A *)INTERNAL_CALLOC(..., sizeof(A));
Here you are lying to the compiler. You are telling it that the return value from INTERNAL_CALLOC points to an A, but it doesn't, it just points to zeroes. Use new.
You don't get a valid std::map<whatever...> by filling memory with zero bytes.
To a certain extent, it's possible with POD types (approximately, "pure C" data structures).
Since you use std::map as a member,
I recommend to use std::vector instead of plain array to be the container.
You can do as follow:
struct A
{
std::map<int, int> B;
};
std::vector<A> vecofmap;
A elem0;
A elem1;
A elem2;
vecofmap.push_back(elem0);
vecofmap.push_back(elem1);
vecofmap.push_back(elem2);
vecofmap[0].B[0] = 100;
std::cout << vecofmap[0].B[0] <<std::endl;
Then no needs to bother with memory allocation.
Allocating memory using malloc does not initialize the array elements.

Will memory of array member of a class be allocated?

I wonder whether memory for array member of a class be allocated in c++.
In my class, I defined array member like this:
class A
{
public:
B* B_array[1000];
}
and, in the constructor, I want to use it:
A::A()
{
for(int i = 0; i < 1000; i++)
{
B_array[i] = new B;//can i use B_array[0...999]???
}
}
B* B_array[1000];
What you have is an array of 1000 pointers to the type B.
for(int i = 0; i < 1000; i++)
{
B_array[i] = new B;//can i use B_array[0...999]???
}
Allocates memory to each pointer in the array, after this statement each pointer points to a memory on heap.
So yes you can use each of them, once this code is executed.
Yes, you can. When you enter the body of constructor, there are 1000 uninitialized pointers waiting for you to initialize them.
What you should do, though, is use std::vector<B>
class A
{
public:
std::vector<B> array;
}
A::A() : array(1000) {}
and be done with it. Vector allocates its elements dynamically.
Yes you can. Memory for 1000 pointers will be allocated always. However those pointers will not be initialised unless you do that yourself (as you are in your contructor code).
I wonder whether memory for array member of a class be allocated in c++
Yes, why not. If your doubt is about allocating an array the way you are doing, it is possible. If your doubt is about calling B's constructor while still being in A's constructor, then also there is absolutely no issues with that.
In general, however there are several things that I would take care in the code shown e.g. not hard coding the value 1000, checking for exception from new etc.. you get the idea.
And you should also be bothered about releasing the memory resource in the destructor of A explicitly.
Yes, the memory for 1000 pointers of B class instances will be allocated. You have defined an array B_array[1000] of B* objects. It's the same as int integerArray [1000]. You just store pointers in the array, not values.
However you will need to initialize them to point to the actual objects on the heap.

C++ variable array as class member

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.