Array declaration and size initialization (C++) - c++

I'm not exactly sure how to pose this question so I'll start with some example code:
//header file
class A
{
public:
A();
private:
int x;
std::string arr[x];
}
//cpp file
class A
{
public:
A()
{
/*code to get the value of x from a cmd call*/
}
}
Is this code valid? More specifically, can I have my string array in my header file be of size x, even though x is not specifically given a value until an A object has been created?
If this doesn't work, is my only other option to use a dynamically allocated array?

The code is not valid. You should use a vector instead.
class A
{
public:
A();
private:
int x;
std::vector<std::string> arr;
};
A::A () : x(command_gets_x()), arr(x) {}
Since arr is being initialized by the value of x, the constructor only works when x precedes arr in A (as it is in your definition). However, if the only purpose of x is to track the size of the array, it is not necessary, since a vector has the size() method.
class A
{
public:
A() : arr(command_gets_x()) {}
int x () const { return arr.size(); }
//...
private:
std::vector<std::string> arr;
};

It's not valid. Array sizes must be constant expressions. Yes, you'll have to use dynamic allocation, though not necessarily directly. You can just use std::vector.

No, that's not possible, for one C++ doesn't have variable length arrays, and further, the array size must be a compile time constant.
You can in the constructor allocate an array with new, or, better use a std::vector.

No, you can't initialize arrays with non-const expressions. This will work, and is close to your original intent:
class A
{
...
const int x = 3;
std::string arr[x];
};
And in the .cpp file:
int A::x;

I found that on my mac, in x-code I could do the following
int x = foo() // get some value for x at runtime
int array[ x ];
but that is seriously uncool!! I just read yesterday that some compilers allow dynamic allocation on the stack, but I would recommend that you stay well clear of that.
If the value of x is not known until runtime, then you cannot allocate an array of size x until runtime. Think about what the compiler does: can an array of size x be allocated if we don't know how big x is? The only remaining option is to allocate at run-time (aka dynamically allocate).

Related

Is there any way to use parameters from the constructor in a c++ header Flie

i want to use values ​​that I declare in the constructor with passed variables in the Header file. Is that somehow possible? In my case I give the constructor two int values ​​with these values ​​I want to set the size of a array. Was there a way to do that in the header file? Like this:
class test
{
public:
test(int valueA); //Constructor
float testArray [valueA]; //Array
}
No you can't do it like this and no, that's not even legal C++. The size of an array must be known at compile time. You should use std::vector<float> instead and initialize it in the constructors initializer list:
#include <vector>
class test
{
public:
test(int valueA) : testArray(valueA) {}
std::vector<float> testArray;
}
This will initialize testArray with valueA values.
As written: no.
Two options:
Use a class that doesn't need it's size set (like std::vector). This is the better approach.
Or dynamically create the array once you do know the size. This isn't a great approach, but may be closer to the intent of the original question. As pointed out in the comments to avoid dynamic memory issues, since there is a destructor you probably want a copy constructor and a copy assignment constructor to ensure you don't end up with two text classes sharing the same array.
class test
{
public:
test(int valA)
{
testArray = new float[valA];
}
~test()
{
delete[] testArray;
}
private:
float* testArray
};

Set array field's length based on const integer field

Suppose I have a class...
class Foo
{
public:
Foo(int size);
private:
const int size;
int data[];
};
Supposing that the size field is set immediately at instantiation, how can I set the length of data based on that size input?
I would ordinarily use a std::vector here, but I am writing a library for Arduino, so that won't fly, and I'm trying to avoid external dependencies if I can.
You are out of luck here, as C++ must know the size of the array at compile time (in other words, the size must be a constant expression). Your options are to either use dynamic allocation
int* data;
then allocate with new int[size]; in the constructor initialization list, or, better, use std::unique_ptr<> (C++11 or later), which is a light wrapper around a raw pointer and deletes its allocated memory at scope exit, so you won't have to manually delete[]
class Foo
{
private:
std::unique_ptr<int[]> data; // no need to manually delete
public:
Foo(int size): data{new int[size]} {}
};
A third option is to make Foo a non-type template class (assuming you know the size at compile time, which is what it seems to be happening, at least judging from your question)
template<std::size_t size>
class Foo
{
int data[size];
public:
Foo()
{
// constructor here
}
};

Array as a data member

I want to have a class that contains an array as it's data member. The size of the array is declared during construction. I know that the size of an array needs to be known at compile-time, but is there no way to work around this by using a const int to define the size and subsequently using constructor initializer list? I'm not allowed to use vectors. This is my futile attempt:
#include <iostream>
using namespace std;
class myArray {
public:
myArray(int size) : capacity(size) {}
private:
const int capacity;
int a[capacity];
};
int main() {
myArray ar(25);
return 0;
}
It gives the following error:
'capacity' was not declared in this scope
Try to use pointer instead
#include <iostream>
using namespace std;
class myArray {
public:
myArray(int size) : capacity(size) {array = new int[capacity];}
~myArray() {delete [] array;}
private:
const int capacity;
int* array;
};
int main() {
myArray ar(25);
return 0;
}
And don't forget to release in the destructor.
All of the above answers are "technically correct", but none actually show the usage of a smart pointer which makes all of the additional memory management unnecessary.
class my_array
{
public:
my_array (size_t sz)
: arr {new int [sz]} {}
pirvate:
std::unique_ptr <int[]> arr;
};
Now you needn't concern yourself with the rule of (3 or 5), and the code is correct and (mostly) exception safe.
It could work with a static const but you would lose the constructor argument setting. You have to allocate it dynamically for it to work:
class myArray {
public:
myArray(int size) : capacity(size)
{
a = malloc(size * sizeof(int));
}
~myArray() { free(a); }
private:
int capacity;
int* a;
};
int main() {
myArray ar(25);
return 0;
}
Although allocating with new [] and freeing with delete [] is probably more C++ than malloc and free.
As stated in some comments, if you dynamically allocate and don't use automatic resource management objects like shared_ptr or unique_ptr, you have to follow the rule of three.
The problem with your original class is that it allows for different values to be passed in as the capacity. Hence, you cannot create an array with that value, in the way you want. It makes no difference that you only create one instance with a size of 25, that's a property of the program, and the class itself doesn't know it's only used that way.
Now I'm not going to question why you can't use a vector but it seems a shame to not use the full capabilities of the language/library.
However, given your restrictions, you can create an array dynamically rather than trying to create a fixed array:
#include <iostream>
using namespace std;
class myArray {
public:
myArray(int size) : capacity(size) {
a = new int[capacity];
}
~myArray() {
delete[] a;
}
// Also need all those other things, mandated by the
// rule of 3/5, to allow proper deep copy/move:
// - copy constructor.
// - copy assignment operator.
// - move constructor (C++11).
// - move assignment operator (C++11).
private:
const int capacity;
int *a;
};
int main() {
myArray ar1(25);
myArray ar1(42);
return 0;
}
By passing in capacity as a variable, you have a dynamically sized array (whose size is only known at runtime). This means that sizeof(myArray) is unknown to the compiler, which will cause problems.
Instead, you will need to store a pointer to an array.
Another (ugly) approach would be to use a placement strategy, place the array at the end of the struct/class, and give it a constant size of 1, as shown here
constness is insufficient, because you can even take a value that's provided by the user during execution of the program and make it const:
int x;
std::cin >> x;
const int y = x;
It's insufficient because the array dimensions must be known when the program is compiled.
Historically, if you were to initialise a static const "variable" at the point of declaration, then this would be enough to convince the compiler that it could use that value for an array dimension:
static const unsigned int N = 5;
because there's no way that can go wrong.
Nowadays, we have constexpr for the purpose of making this absolutely explicit.
You can use Template non-type arguments (only works for C++). Take a look at this page and example:
https://www.ibm.com/docs/en/zos/2.1.0?topic=arguments-template-non-type.

Providing the size (const) of the member array as the constructor argument RELOADED

I have gone through some of the threads on the same topic but they are really advanced like set and all. For someone just finding his footsteps in C++, what would be the best way to deal with this?
The following code gives me error:
class AStack {
public:
AStack(int size) : max_Size(size) {
}
void push(int);
int pop();
int top();
bool isEmpty();
void Flush();
private:
const int max_Size;
int a[max_Size];
int index = -1; // Index of the top most element
};
You have 3 options here.
Turn the class into a template and the depth parameter becomes a template argument. Then it is constant and you can create the array with respective size.
Use a std::vector for your internal array and use the resize() method.
Make max_depth a static const uint32_t max_depth = 42; (Initialize in-class) and then you can use that max_depth, too as size for array a.
Solution 1 looks then like this:
template <size_t max_depth>
class AStack
{
// ...
int a[max_depth];
};
Solution 2 then looks like this:
#include <vector>
class AStack
{
public:
AStack( size_t max_depth )
{
a.resize(max_depth);
// ...
}
// ...
std::vector<int> a;
// ...
};
Solution 3 would look like that:
class AStack
{
static const int max_depth = 42;
int a[max_depth];
// ...
};
Fixed size c-arrays can only be declared with a constant array size expression.
The constructor affects the non static members of a class. The static const members of a class are "hard-coded" initialized.
So if you want to allow users of that class to use it with varying stack sizes, you need option 1 or option 2. If you want to hard-code the stack size within the class, use option 3. Option 2 can also be done "manually" using operator new() or new() instead of a std::vector. But then you have much more to type, to check, and you will most likely have bugs which will not impress your instructor ;)
Evidently this is a learning exercise, so the straight-forward solution with std::vector doesn't work for you. That means you need to use pointers and dynamic allocation.
Declare the array as a pointer instead:
int * a;
In the constructor, allocate the appropriate size array:
AStack(int size) : max_Size(size), a(new int[size])
And whenever you allocate memory, you need to free it when you're done with it. In this case, in the destructor.
~AStack() {
delete [] a;
}
Because the destructor is no longer trivial, the rule of three suggests that you need a copy constructor and assignment operator too. I'll leave that part to you.

Constructor initilizer list for a class with multiple arrays (C++11 is ok, boost and std::vector are not)

I don't understand the new C++11 syntax yet for initializing an array in a constructor initilizer list. I'm no longer stuck with C++03 but I can't use boost or std::vector because of program constraints.
An instance of FOO must be sized by the constructor call and behave as though the sizes of x and y were statically known. Does the new C++11 features allow this?
I'm not sure if or how std::initializer_list<> can help.
class FOO
{
public:
// this constructor needs to size x = count and y = count * 4
FOO(int count) :
{
// interate over x and y to give them their initial and permenent values
}
private:
const BAR x[];
const TAR y[];
};
#include "foo.h"
void main(void)
{
// both need to work as expected
FOO alpha(30);
FOO * bravo = new FOO(44);
}
You can't do what you're trying to do. The sizes of arrays must be compile-time constants. And while the values provided to the constructors in your particular use cases may be compile-time constants, C++ can't know that.
Furthermore, as a statically-typed language, C++ requires being able to compute the size of the class at compile-time. sizeof(Foo) needs to have an exact, single value. And your's can't.
Initializer lists aren't going to help you. You want two runtime-sized arrays; that's what std::vector is for. If you want compile-time sized arrays, you need to use a template type:
template<int count>
class FOO
{
public:
FOO(initializer_list<Whatever> ilist)
{
// interate over x and y to give them their initial and permenent values
}
private:
const BAR x[count];
const TAR y[count * 4];
};
#include "foo.h"
void main(void)
{
// both need to work as expected
FOO<30> alpha;
FOO<44> * bravo = new FOO<44>;
}
Besides the answer from Nicol Bolas using template parameters to make the size compile-time configurable, you can also allocate memory on the heap:
class FOO
{
public:
// this constructor needs to size x = count and y = count * 4
FOO(int count) : x(new BAR[count]), y(new TAR[count])
{
// interate over x and y to give them their initial and permenent values
}
// Need a destructor to free the memory we allocated in the constructor
~FOO()
{
delete [] y;
delete [] x;
}
private:
const BAR* x;
const TAR* y;
};