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)
{
}
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.
This is driving me around the bend. All the documentation on vectors is ridiculously deep.
In a class I want to declare a vector equal in length to the length of a string I've already declared. It sounds easy enough.
If I use:
class Test {
private:
size_t size = 10;
std::vector<int> array(size);
};
I get "only static const integral data members can be initialized within a class"
If I:
std::vector<int> array(anarray.length());
I get the fantastically unhelpful:
error C2061: syntax error : identifier 'anarray'
How do I do it?
In-class initialization requires use of the type var = value; syntax or the uniform initialization syntax.
For your needs, it is more appropriate to use type var = value; syntax.
class Test {
private:
std::size_t size = 10;
std::vector<int> array = std::vector<int>(size);
};
You can initialize size using:
std::size_t size{10};
However, if you use
std::vector<int> array{size};
it will try to create a std::vector with one element containing the value of size. That's not what you are interested in.
Judging by bits and pieces scattered across comments to different answers, I figured out that OP does not use C++11 and does not need dynamic array capability. Because of that, my advice is to go with good ol' C-style static arrays. Following code would do the trick:
struct Test {
static const size_t array_sz = 10;
int my_array[array_sz];
};
If, by nature of being an assignment from moronic CS teacher, an std::vector is mandated, this is how it should be initialized:
struct Test {
static const size_t array_sz = 10;
std::vector<int> my_array;
Test() : my_array(array_sz) {}
};
Explanation: std::vector needs to be constructed with a certain argument to specify it's size. Pre-C++11 the only way to call a specific constructor of a member variable was to do this in the so-called initializer list of the constructor of the enclosing class.
After C++11, this can also be done directly in site of member definition. But you need a compiler which is less than 6 years old for this.
Just declare std::vector<int> array and if you want you vector not be larger that one specific size create a method that check the vector size before insert.
Data members are usually initialized in the member initialization list:
class Test
{
std::vector<int> array;
public:
Test() : array(10)
{ // ^^^^^^^^^
}
};
Like this: (requires c++11 or better)
class Test {
private:
size_t size = 10;
std::vector<int> array = std::vector<int>(size);
};
Just get rid of the (size). The vector doesn't have, or have to have, a length until at least one instance of it exists. The number of elements in a vector is not part of its type. A std::vector<int> can contain no integers or a hundred integers -- it's still a std::vector<int>. When declaring that the vector is a member of the class, the number of members that instances of that vector will have, later when they exist, doesn't matter.
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 want to statically allocate the array. Look at the following code, this code is not correct but it will give you an idea what I want to do
class array
{
const int arraysize;
int array[arraysize];//i want to statically allocate the array as we can do it by non type parameters of templates
public:
array();
};
array::array():arraysize(10)
{
for(int i=0;i<10;i++)
array[i]=i;
}
main()
{
array object;
}
If your array size is always the same, make it a static member. Static members that are integral types can be initialized directly in the class definition, like so:
class array
{
static const int arraysize = 10;
int array[arraysize];
public:
array();
};
This should work the way you want. If arraysize is not always the same for every object of type array, then you cannot do this, and you will need to use template parameters, dynamically allocate the array, or use an STL container class (e.g. std::vector) instead.
It has to be done using template parameters, otherwise sizeof(array) would be different for every object.
This is how you would do it using template parameters.
template <int N>
class array
{
int data[N];
// ...
};
Or, you could use an std::vector if you don't mind dynamic allocation.
C++ doesn't allow variable-length arrays (i.e. ones whose sizes are not compile-time constants). Allowing one within a struct would make it impossible to calculate sizeof(array), as the size could differ from one instance to another.
Consider using std::vector instead, if the size is known only at runtime. This also avoids storing the array size in a separate variable. Notice that allocating from heap (e.g. by std::vector) also allows bigger arrays, as the available stack space is very limited.
If you want it a compile-time constant, take a template parameter. Then you should be looking for Boost.Array, which already implements it.
The array size must be a compile time constant. You are almost there, you just need to initialize the const and make it a static as well. Or, use a dynamic array or a vector.
EDIT: note about this answer: This is most likely the wrong way to do this for your situation. But if you really need it to be an array (not a vector or whatever) and you really need it to be dynamically allocated, do the following:
class array
{
int *p_array;
public:
array(int size);
};
array::array(int size)
{
p_array = malloc(size * sizeof(int));
}
Just make sure you clean up (IE free p_array in your descructor)
I was wondering if it is possible to declare an array (size not known at this time), as a private member of a class and later set the size in the constructor of the class. For example:
class Test {
int a[];
public:
Test(int size);
};
Test::Test(int size) {
a[size]; // this is wrong, but what can i do here?
}
Is this possible or should I use dynamic arrays? Thanks!
Short Answer: No (The size of an array is defined at compile time only)
Long Answer:
You can use a vector to achieve the same result:
class Test
{
std::vector<int> a;
public:
Test(std::size_t size):
a(size)
{}
};
No this is not possible. Array declarations in headers must have constant sized value. Otherwise it's impossible for constructs like "sizeof" to function properly. You'll need to declare the array as a pointer type and use new[] in the constructor. Example.
class Test {
int *a;
public:
Test(int size) {
a = new int[size];
}
~Test() { delete [] a; }
private:
Test(const Test& other);
Test& operator=(const Test& other);
};
As other answers have pointed out, the size of an array is fixed at compile time. However, by using templates you can parameterise the size at compile time:
template <int N> class Test {
int a[N];
public:
Test() { }
};
Test<5> test;
Test<40> biggertest;
This technique does not let you compute the size at run time (as the dynamic std::vector solution does), but depending on your needs this may be sufficient.
First of all, it is generally better to initialize things in the initialization list of the constructor, not in the body of the constructor.
You can only initialize an array with a predefined bound if you know that bound at compile time. In this situation, you will need to dynamically allocate the space.
You must remember then to have a destructor that would delete the array when the object is destroyed or you would get a memory leak.
See Martin's solution (use std::vector), and remember that even if you need to pass a buffer to a C API std::vector lets you do it by passing &vec[0] :
std::vector<char> vec(10);
memset(&vec[0], 0, vec.size());
It's guaranteed to work, but only if the vector isn't empty (C++ quirks, <sigh>).
No, this is not possible. You should use a dynamic array such as an std::vector. C99 allows a struct to have an unsized array as the last member only, but even when you do this you still have to manually allocate the memory yourself, e.g. with malloc().
What you're talking about is not possible. Classes always have a constant size. You could have your class use a pointer to a dynamically allocated array or you could use a std::vector.