Let's say I have a class that includes an array of some struct, and a pointer to that array.
struct Box {
//stuff
};
class Foo {
private:
Box *boxPtr //pointer to an array of Box structs
int max; //the size of the partially filled array
int boxCounter; //the current number of non-NULL elements in the array
public:
Foo(); //constructor
Foo(const Foo &obj); //copy constructor
~Foo(); //destructor
bool newBoxInsert(Box newBox){
//adds another Box to my array of Box structs
boxCounter++;
}
//etc
};
and in my int main(), I somehow must create a brand new object of class Foo.
I'm going to need to partially fill that array of indeterminate size, whose pointer is boxPtr.
How would I go about initializing that array? Should the constructor do it? Or should I let newBoxInsert handle it?
In either case, how would I achieve that? I'm guessing I would have to dynamically allocate the array. If that's the case, then it's good to have the pointer as a class member... right?
For example, when adding the very first element to my array, should I use
boxCounter = 1;
boxPtr = new Box[boxCounter];
then continue on to keep adding elements to the array?
Perhaps this is just better done with vectors. They're much more... flexible (?) when adding elements. Can vectors contain structs as elements?
[/n00b]
private:
Box *boxPtr
replace this by:
private:
std::vector<Box> mbox;
It saves you all the manual memory management. And you are less likely to go wrong.
Yes, std::vector can contain structs as elements. In fact it is a template class so it can store whatever data type you want.
In C++ if you need dynamic array, the simplest and most obvious choice us std::vector.
Related
I need to use array as a class property but I am not sure about the correct way. Assume that I have a class called A and I need an integer array in it.
First, if I want a static array with 10 elements, is the following way correct? If not, how should it be?
class A {
public:
int arr[10];
};
Second, if I want a dynamic array, which one of the followings is correct? If neither of them, I would be appreciated if you explain the reason and correct way.
class A {
public:
int *arr;
};
class A {
public:
int arr[];
};
Finally, what happens if I initialize a property in class definition as following
class A {
public:
int arr[] = {1,2,3};
// or
int *arr = new int[5];
// or
int number = 5;
};
Thanks a lot.
Note: I am aware of that it is much better to use vector or that kind of STL data structure but I need to stick to arrays somehow.
First, if I want a static array with 10 elements, is the following way correct?
Yes, that is a correct way.
Some people prefer to wrap the array in a class template such as std::array.
Second, if I want a dynamic array, which one of the followings is correct? If neither of them, I would be appreciated if you explain the reason and correct way.
class A {
public:
int arr[];
};
That is an ill-formed declaration. A member cannot be an array of indeterminate length.
class A {
public:
int *arr;
};
This is correct as such, but there is no dynamic array created. Using this for owning a dynamic array is bad design because bare pointers should never have ownership.
Even for pointing an array stored elsewhere, this is problematic since the class has no knowledge of the length of the array.
This would be a correct way, assuming the array is owned by the class:
class A {
public:
std::vector<int> arr;
};
If the array isn't owned by the class, then following is correct:
class A {
public:
std::span<int> arr;
};
std::span isn't in the standard until C++20 though, so until then you need to resort to a non-standard implementation.
Finally, what happens if I initialize a property in class definition as following
class A {
public:
int arr[] = {1,2,3};
That is ill-formed because the size of a member cannot be deduced from the initaliser.
int *arr = new int[5];
new int[5] is a default member initialiser. It will be used in case no initialiser is provided for the member otherwise.
For fixed-size arrays you can use int arr[10] or std::array<int, 10>.
For dynamically-sized or resizeable arrays if you cannot use std::vector or std::unique_ptr<int[]> you should use int* (int[] is not a valid data member type in C++) and implement constructor, copy constructor, move constructor, copy assignment, move assignment and destructor. See rule of five for more details.
I would like to know, if I have a class with an array attribute whose size is not the same for all instances :
class myObject{
private:
int size;
int* array;
// other methods/attributes
};
Is it obligatory allocated using new ?
explicit myObject(int size = 0):size(size){
array = new int[size];
}
Even if in the main(), I always use constant parameters to create the instances of the class ? (Meaning I know every array size at compile time).
int main{
myObject object (5);
return 0;
}
Apparently something like :
private:
int size;
int array[size];
wont work, no ?
That means that array attribute whose size are not constant of the class are obligatory on the heap ?
Thank you for your answers,
That class contains no array. What you called array is a pointer; you cannot store any ints in it. If you really do just store a pointer, you'll have to allocate the memory yourself somehow; it can't magically appear. You'll also have to deallocate it yourself, and make sure that copying and assigning myObject objects doesn't cause any issues.
However, it's unlikely that a pointer is really the best way to do things. The standard library provides the std::vector class template which lets you use almost exactly the syntax you want:
class myObject {
std::vector<int> vector;
public:
myObject() {};
explicit myObject(std::size_t n) : vector(n) {}
};
With this in place you can create myObjects and they'll have the right amount of storage ready for them. It'll likely be dynamically allocated using operator new[], just like if you'd do it manually, but you don't have to worry about copying or deleting it.
int main() {
myObject a; // default-constructed, vector is empty.
myObject b(10); // std::size_t constructor, vector has 10 elements.
} // scope exit, b and a destroyed.
You can use the vector member much like if it was an array; the only thing it does not support is implicit decay to pointer, but the data member function makes up for even that.
As an alternative, if you always know the size at compile-time you can change the class into a class template and make the size a template parameter:
template<std::size_t N>
class myObject{
std::array<int, N> array;
// other methods/attributes
};
However, note that you now cannot use myObject<10> to a function expecting myObject<20>.
It is unlikely that you want more control than the above possibilities provide -- std::vector can be given an allocator, so it can do almost all work for you -- you could use std::unique_ptr<int[]> and make_unique together to make things work for you. However, if you need this kind of power, you probably know it yourself.
As a closing note, if you're just learning C++ and your book doesn't cover std::vectors somewhere early on, perhaps it's best to get a different book; they're one of the most commonly-useful data structures in the standard library and definitely not something to be left in an appendix.
If you need a variable sized array as a member of a class, don't use built-in arrays directly. Instead, use std::vector<T>, e.g.:
class myObject {
std::vector<int> array;
public:
explicit myObject(int size = 0): array(size){}
};
You can get the std:vector<int>'s size using array.size(), i.e., there is no need to store the size separately. Also, the content is automatically default initialized.
I'm having trouble understanding what an internal array means. I have an assignment that ask to implement a standard queue class using internal array and set the array to 12. Is internal array another word for dynamic array, static array, ...? What is internal array? Also, what is a fixed size array inside object. This is on c++.
I thought is was asking to use a static array, fixed size array and pass by reference. As they are many ways to write a queue, just not sure which one does internal array falls under
cont int capacity = 12;
typeddef int element;
class Queue
{
public:
...
void add(const element &value);
private:
...
element myArray[capacity];
}
Now I'm being told by a classmate that it means a fixed size array inside object.
public class StandardQueue
{
private Array _array = new Array(); // This is the encapsulated member
public void WorkWithArray()
{
// Work with the array here
}
}
In this example the member called _array is only accessible from within the class StandardQueue. This means that if you create an instance of StandardQueue you would be able toa ccess function WorkWithArray but not _array. All access to _array must happen from within the class (e.g. inside the functions).
I have currently a VERY BIG structure >13MB (and it HAS to remain like that, because I can't have pointer). My problem is how to store it into a class.
If it is part of the class, I get stackoverflow. If I use pointers the problem is solved, until I need to start copying the classes.... then the hell starts. (since the class has a lot of members).
I tryed with STL vector and array, but I still get the stackoverflow. Is any STL container that does not put the structure in the stack but it directly allocates the memory?
This way I can have everything properly done.
Thanks.
UPDATE:
Example code:
//HEADER
#include <vector>
struct BigStruct { //This is untouchable or divisible into an array of arrays
char a[1000];
int b[1000][1000];
long c[1000000];
// etc...
};
class Foo
{
std::vector<BigStruct> a; //It has to be here since is related to this instance of the class
public:
Foo();
//All the other funcs and method
// ...
//All the other variables are from STL
// ...
};
//CPP
Foo::Foo(){
a.resize(1);
}
I am just answering my own question. When calling resize() std::vector creates a element of type BigStruct in the stack and then copies it the number of times specified.
This behaviour can be avoided by creating the element in the vector like this:
Foo::Foo(){
BigStruct * temp = new BigStruct;
a.clear();
a.push_back(*temp); //Element is reserved and copied directly from temp.
delete temp;
}
This completely solves the stack issue, and allows portability(copy, move destroy) of the parent class.
Let's say I have a class that has a member which is an array. Is it possible to define its size upon construction/at run-time, in the following way:
class myClass {
private:
int myArray[n]
public:
myClass();
someOtherMethod();
};
Where n is a variable that is defined based on user input. If not, what would be the best alternative?
It depends.
Semantically, there are 3 types of arrays:
arrays with a size fixed at compile time
arrays with a size fixed at runtime
arrays with a dynamic size
C++ directly supports the first and third cases, respectively with regular arrays and the std::vector class.
C also supports the second type with two constructs:
variable length arrays (on the stack)
the oldie struct hack or tail-padding
I would advise, in C++, using the std::vector class in your case. It provides more than what you need, but is simpler to use.
On the other hand, you can still use tail-padding, even in C++. It does require careful engineering though.
Use a vector.
class myClass {
private:
std::vector<int> myArray;
public:
myClass();
someOtherMethod();
};
myClass::myClass (int size)
: myArray (size)
{
...
}
Then, you can fill in the vector as you would an array. Alternatively, as Nawaz points out, use reserve(), which reserves space for new elements, and/or push_back(), which adds elements onto the back, one at a time.
The class template std::vector is designed for this purpose.
class myClass {
private:
std::vector<int> myArray;
public:
myClass(int size);
someOtherMethod();
};
myClass::myClass(int size) : myArray(size)
{
}