As a C++ beginner, I oftentimes find myself struggling with the declaration of class attributes inside the header file that need more information than just a name, like arrays and objects of other classes with constructors.
Here's an example
SomeClass.h :
#include "OtherClass.h"
class SomeClass {
int num; // works fine
float arr[]; // produces an error because size is not declared
OtherClass obj; // produces an error because the constructor parameters are not passed in
public:
void setup();
void update();
};
SomeClass.cpp:
#include "SomeClass.h"
void SomeClass::setup() {
num = 10; // easy peasy, works!
arr = float some_arr[5 * num]; // error
// Fill in the array
for (int i = 0; i < 5 * num; i += num) {
ass[i] = 12;
}
// Fill in the class attributes
obj = {120, 40}; // error
}
void SomeClass::update() {
// Update stuff
}
In case of the array arr, how can I declare an array, if I don't know it's size at the moment of the declaration in the header file?
How can class objects with constructors be declared in the header file, without passing in unknown parameters at that moment?
Thanks.
In case of the array arr, how can I declare an array, if I don't know
it's size at the moment of the declaration in the header file?
You can't! C++ does not support variable length arrays, although some compilers (such as GCC) add support for them as an extension.
Instead, you should consider using the std::vector container type, from the Standard Template Library.
In your header/declaration:
class SomeClass {
int num; // works fine
// float arr[]; // produces an error because size is not declared
std::vector<float> arr;
//...
};
And, for your setup() function:
void SomeClass::setup() {
num = 10; // easy peasy, works!
// arr = float some_arr[5 * num]; // error
arr.resize(5 * num); // Sets the size of the container
// Fill in the array...
for (int i = 0; i < 5 * num; i += num) {
arr[i] = 12; // You can access (valid) elements just like a normal array!
}
//...
}
In case you don't know the array size before hand you can use dynamic allocation feature in C++.
First declare your array variable as follow
float *arr;
Then you can allocate required size as follows
arr=new float[10];
To deallocate memory
delete[] arr;
If want to dynamically allocate objects then,Declare class as
ClassName *obj;
Then to allocate use
obj=new ClassName(your_parameters);
Then you can delete it using
delete obj;
TIP:
It is always a good practice make pointer variable NULL after you have de-allocated memory.
Do arr=NULL; and obj=NULL; after de-allocating
Related
I have really been struggling with a piece of code for a couple days. The error message i receive when i run my code is:
error: array initializer must be an initializer list
accountStore (int size = 0) : accts(size) { }
There seem to be others with similar problems here but unfortunately I am unable to apply their solutions (either don't work or not applicable).
What I am simply attempting to do is create a container class (array, can't use vectors) of a class 'prepaidAccount' but I am just unable to get the constructor portion of the container class 'storeAccount' to work. See code snippet below:
class prepaidAccount{
public:
//prepaidAccount ();
prepaidAccount(string newPhoneNum, float newAvailBal) : phoneNumber(newPhoneNum), availableBalance (newAvailBal){} //constructor
double addBalance(double howMuch) {
availableBalance = howMuch + availableBalance;
return availableBalance;
}
double payForCall(int callDuration, double tariff) {
callDuration = callDuration/60; //convert to minutes
double costOfCall = callDuration * tariff;
if (costOfCall > availableBalance) {
return -1;
}
else {
availableBalance = availableBalance - costOfCall;
return costOfCall;
}
}
void setAvailBal(int newAvailBal) {availableBalance = newAvailBal;}
float getAvailBal() {return availableBalance;}
void setPhoneNum(string newPhoneNum) {phoneNumber = newPhoneNum;}
string getPhoneNum() const {return phoneNumber;}
private:
string phoneNumber;
float availableBalance;
};
class accountStore { //made to store 100 prepaid accounts
public:
accountStore (int size = 0) : accts(size) { }
....
private:
prepaidAccount accts[100];
}
In main I simply call accountStore Account;
Any help is absolutely welcome. I very recently started learning c++ and about classes and constructors so please bear with me.
Thanks
You can't initialize an array with int like accountStore (int size = 0) : accts(size) {}.
prepaidAccount doesn't have a default constructor, you have to write member initialization list like,
accountStore (int size = 0) : accts{prepaidAccount(...), prepaidAccount(...), ...} { }
The array has 100 elements, it's not a practical solution here.
As a suggestion, think about std::vector, which has a constructor constructing with the spicified count of elements with specified value. Such as,
class accountStore {
public:
accountStore (int size = 0) : accts(size, prepaidAccount(...)) { }
....
private:
std::vector<prepaidAccount> accts;
};
Given that you have specified that you do not want to use a container such as std::vector but would like to specify the size at runtime, your only option would be to manually implement dynamic allocation yourself. Also given that you are wanting create 100 objects at a time, I would suggest making a function that can construct a temporary object according to your needs and then use this to initialise your dynamically allocated array. Consider the below code as a good starting point. (WARNING untested code.)
class prepaidAccount {
public:
// Constructor
prepaidAccount(string newPhoneNum, float newAvailBal)
: phoneNumber(newPhoneNum), availableBalance(newAvailBal) {}
// Default Constructor needed for dynamic allocation.
prepaidAccount() {}
/* your code*/
};
// Used to construct a tempoary prepaid account for copying to the array.
// Could use whatever constructor you see fit.
prepaidAccount MakePrepaidAccount(/*some parameters*/) {
/* Some code to generate account */
return some_var;
}
class accountStore {
public:
// Explicit constructor to avoid implicit type-casts.
explicit accountStore(const int &size = 0)
: accts(new prepaidAccount[size]) {
for (int i = 0; i < size; i++) {
// Will call defualt assignment function.
prepaidAccount[i] = MakePrepaidAccount(/*some parameters*/);
}
}
// Destructor
~accountStore() {
// Cleans up dynamically allocated memory.
delete[] prepaidAccount;
}
prepaidAccount *accts;
};
Edit: Amongst the c++ community it is often questionable when choosing to use dynamic allocation when there is such an excellent and comprehensive library of smart pointers. For example an std::vector would be perfect in this situation.
Can you tell why does this generate segmentation error? Problem seems to occur when operator[] is called and when I don't call it, goes fine. operator[] is supposed to return a reference to the element with index i.. any help would be great..
//dynamic_array.cpp file
#include <iostream>
#include "dynamic_array.h"
using namespace std;
dynamic_array::dynamic_array() {
int *array;
array=new int[4];
array[0]=3;
size = 4;
allocated_size = 5;
}
dynamic_array::~dynamic_array() {
delete [] array;
}
int dynamic_array::get_size(void) const {
return size;
}
int dynamic_array::get_allocated_size(void) const {
return allocated_size;
}
int& dynamic_array::operator[](unsigned int i) {
return array[i];
}
//test.cpp file
#include <iostream>
#include <stdlib.h>
#include "dynamic_array.h"
using namespace std;
int main() {
dynamic_array a;
cout << a[0];
}
//dynamic_array.h file
using namespace std;
class dynamic_array {
public:
enum {
BLOCK_SIZE = 5,
SUBSCRIPT_RANGE_EXCEPTION = 1,
MEMORY_EXCEPTION = 2,
};
dynamic_array();
~dynamic_array();
int get_size(void) const;
int get_allocated_size() const;
int& operator[](unsigned int i);
class exception {
public:
exception(int n0) { n = n0; };
int n;
};
private:
int *array; // pointer to dynamically allocated memory
int allocated_size; // total number of elements in allocated memory
int size; // number of active elements
};
The local declaration
int *array;
shadows the member array. So the following code uses the local variable, not the member. Hence the member is uninitialized.
Instead of creating your own dynamic array, use std::vector.
That's safer and more convenient.
In other news:
The get prefix in e.g. get_size is a Java-ism.
In C++ a get prefix has no advantage, and it makes the code less readable. For example, standard library containers have a size method, not a get_size.
Using void as a formal argument declaration, as in get_size(void), is a C-ism.
In C it has the important effect of telling the compiler that there really are no arguments, as opposed to any arguments. In C++ () indicates that.
Not having also a const version of operator[] is inconsistent with earlier use of const.
Consistency is very important in programming. Our expectation, e.g. when maintaining code, is that it's consistent. Code that's inconsistent adds costly man-hours to maintenance.
The ALL UPPERCASE identifiers for constants are a Java-ism.
Java lacks a preprocessor, and inherited the all uppercase convention from early C, which lacked const. C++ has both const and a preprocessor. Having const there's generally no need to use #define for constants (as in early C), and having a preprocessor there's a good tecnical reason to not use all uppercase (it conflicts with the convention for macro names). In addition many/most programmers see all uppercase as shouting. It hurts.
The class exception should better be derived from std::exception.
Instead of inventing one's own exception class that can carry an error code, just use std::system_error. That's what it's for. Alternatively, derive a class from std::runtime_error, or use std::runtime_error directly.
The problem is in your constructor
Go like this for the constructor:
dynamic_array::dynamic_array() {
array = new int[4];
array[0] = 3;
size = 4;
allocated_size = 5;
}
the problem is this additinal line of code in the constructor:
int *array;
In your constructor definition, you declared a new local pointer variable named array and you allocated memory for that.
But this variable is local to the constructor and it is not the one declared in your class as may be you believed.
I want to define dynamic array h of size size and later in other functions, modify and use it as here:
class definition:
static int size=10;
class hash{
public:
string h[size];
hash();
void resize();
void operations();
void print();
};
hash::hash()
{
h[size-1]="nikhil"; //size=10 now.
}
/*Defining `h` as `string* h=new string[size];` is not working.
My compiler (MinGW on Windows 7) show error: dynamic allocation is not allowed by default*/
// resizing the array
void hash::resize( )
{
string temp[2*size];
for(int i=0;i<=size;i=i+1)
{
temp[i]=h[i];
}
size=2*size;
h=temp;
}
void hash::print()
{
for(int i=0;i<size;i=i+1)
{if(!h[i].empty())
{cout<<"h["<<i<<"]="<<h[i]<<endl;}
}
}
int main()
{
hash p;
p.resize();//now size should change to 20.
p.print();
}
Where is the problem is it defining the size variable or in resizing the array?
Use std::vector if you need arrays of dynamic size.
class hash {
public:
std::vector<std::string> h;
hash();
void resize();
void operations();
void print();
};
hash::hash() : h(10) {
h[9] = "nikhil";
}
void hash::resize() {
h.resize(2 * h.size());
}
Though note that std::vector does resizing for you automatically if you add new elements using push_back. Also note that the standard library has hash table data types already (std::unordered_set and std::unordered_map), so you don’t have to write them yourself.
I do not know C++ but you haven't exactly told what is going on.
But the way your resize() method is working is the for loop goes through 2*the size of H which will cause a problem.
When you loop through 2*size it is trying to loop through more items than what you actually have in the original array. you have to loop through the original array size.
for(int i = 0; i < h.size(); i++)
{
temp[i] = h[i];
}
I can barely see the comments in your code they are too light for me so I didn't see them.
But to explain a little better i guess, lets say original array is size 5 your new one is size 10 when you loop through 10 items you dont have 10 items in the original array so you'll get errors when trying to access them.
I'm having this problem for quite a long time - I have fixed sized 2D array as a class member.
class myClass
{
public:
void getpointeM(...??????...);
double * retpointM();
private:
double M[3][3];
};
int main()
{
myClass moo;
double *A[3][3];
moo.getpointM( A ); ???
A = moo.retpointM(); ???
}
I'd like to pass pointer to M matrix outside. It's probably very simple, but I just can't find the proper combination of & and * etc.
Thanks for help.
double *A[3][3]; is a 2-dimensional array of double *s. You want double (*A)[3][3];
.
Then, note that A and *A and **A all have the same address, just different types.
Making a typedef can simplify things:
typedef double d3x3[3][3];
This being C++, you should pass the variable by reference, not pointer:
void getpointeM( d3x3 &matrix );
Now you don't need to use parens in type names, and the compiler makes sure you're passing an array of the correct size.
Your intent is not clear. What is getpointeM supposed to do? Return a pointer to the internal matrix (through the parameter), or return a copy of the matrix?
To return a pointer, you can do this
// Pointer-based version
...
void getpointeM(double (**p)[3][3]) { *p = &M; }
...
int main() {
double (*A)[3][3];
moo.getpointM(&A);
}
// Reference-based version
...
void getpointeM(double (*&p)[3][3]) { p = &M; }
...
int main() {
double (*A)[3][3];
moo.getpointM(A);
}
For retpointM the declaration would look as follows
...
double (*retpointM())[3][3] { return &M; }
...
int main() {
double (*A)[3][3];
A = moo.retpointM();
}
This is rather difficult to read though. You can make it look a lot clearer if you use a typedef-name for your array type
typedef double M3x3[3][3];
In that case the above examples will transform into
// Pointer-based version
...
void getpointeM(M3x3 **p) { *p = &M; }
...
int main() {
M3x3 *A;
moo.getpointM(&A);
}
// Reference-based version
...
void getpointeM(M3x3 *&p) { p = &M; }
...
int main() {
double (*A)[3][3];
moo.getpointM(A);
}
// retpointM
...
M3x3 *retpointM() { return &M; }
...
int main() {
M3x3 *A;
A = moo.retpointM();
}
The short answer is that you can get a double * to the start of the array:
public:
double * getMatrix() { return &M[0][0]; }
Outside the class, though, you can't really trivially turn the double * into another 2D array directly, at least not in a pattern that I've seen used.
You could create a 2D array in main, though (double A[3][3]) and pass that in to a getPoint method, which could copy the values into the passed-in array. That would give you a copy, which might be what you want (instead of the original, modifiable, data). Downside is that you have to copy it, of course.
class myClass
{
public:
void getpointeM(double *A[3][3])
{
//Initialize array here
}
private:
double M[3][3];
};
int main()
{
myClass moo;
double *A[3][3];
moo.getpointM( A );
}
You may want to take the code in your main function which works with the 2D array of doubles, and move that into myClass as a member function. Not only would you not have to deal with the difficulty of passing a pointer for that 2D array, but code external to your class would no longer need to know the details of how your class implements A, since they would now be calling a function in myClass and letting that do the work. If, say, you later decided to allow variable dimensions of A and chose to replace the array with a vector of vectors, you wouldn't need to rewrite any calling code in order for it to work.
In your main() function:
double *A[3][3];
creates a 3x3 array of double* (or pointers to doubles). In other words, 9 x 32-bit contiguous words of memory to store 9 memory pointers.
There's no need to make a copy of this array in main() unless the class is going to be destroyed, and you still want to access this information. Instead, you can simply return a pointer to the start of this member array.
If you only want to return a pointer to an internal class member, you only really need a single pointer value in main():
double *A;
But, if you're passing this pointer to a function and you need the function to update its value, you need a double pointer (which will allow the function to return the real pointer value back to the caller:
double **A;
And inside getpointM() you can simply point A to the internal member (M):
getpointeM(double** A)
{
// Updated types to make the assignment compatible
// This code will make the return argument (A) point to the
// memory location (&) of the start of the 2-dimensional array
// (M[0][0]).
*A = &(M[0][0]);
}
Make M public instead of private. Since you want to allow access to M through a pointer, M is not encapsulated anyway.
struct myClass {
myClass() {
std::fill_n(&M[0][0], sizeof M / sizeof M[0][0], 0.0);
}
double M[3][3];
};
int main() {
myClass moo;
double (*A)[3] = moo.M;
double (&R)[3][3] = moo.M;
for (int r = 0; r != 3; ++r) {
for (int c = 0; c != 3; ++c) {
cout << A[r][c] << R[r][c] << ' ';
// notice A[r][c] and R[r][c] are the exact same object
// I'm using both to show you can use A and R identically
}
}
return 0;
}
I would, in general, prefer R over A because the all of the lengths are fixed (A could potentially point to a double[10][3] if that was a requirement) and the reference will usually lead to clearer code.
In the code below I would like array to be defined as an array of size x when the Class constructor is called. How can I do that?
class Class
{
public:
int array[];
Class(int x) : ??? { }
}
You folks have so overcomplicated this. Of course you can do this in C++. It is fine for him to use a normal array for efficiency. A vector only makes sense if he doesn't know the final size of the array ahead of time, i.e., it needs to grow over time.
If you can know the array size one level higher in the chain, a templated class is the easiest, because there's no dynamic allocation and no chance of memory leaks:
template < int ARRAY_LEN > // you can even set to a default value here of C++'11
class MyClass
{
int array[ARRAY_LEN]; // Don't need to alloc or dealloc in structure! Works like you imagine!
}
// Then you set the length of each object where you declare the object, e.g.
MyClass<1024> instance; // But only works for constant values, i.e. known to compiler
If you can't know the length at the place you declare the object, or if you want to reuse the same object with different lengths, or you must accept an unknown length, then you need to allocate it in your constructor and free it in your destructor... (and in theory always check to make sure it worked...)
class MyClass
{
int *array;
MyClass(int len) { array = calloc(sizeof(int), len); assert(array); }
~MyClass() { free(array); array = NULL; } // DON'T FORGET TO FREE UP SPACE!
}
You can't initialize the size of an array with a non-const dimension that can't be calculated at compile time (at least not in current C++ standard, AFAIK).
I recommend using std::vector<int> instead of array. It provides array like syntax for most of the operations.
Use the new operator:
class Class
{
int* array;
Class(int x) : array(new int[x]) {};
};
I don't think it can be done. At least not the way you want. You can't create a statically sized array (array[]) when the size comes from dynamic information (x).
You'll need to either store a pointer-to-int, and the size, and overload the copy constructor, assignment operator, and destructor to handle it, or use std::vector.
class Class
{
::std::vector<int> array;
Class(int x) : array(x) { }
};
Sorry for necroing this old thread.
There is actually a way to find out the size of the array compile-time. It goes something like this:
#include <cstdlib>
template<typename T>
class Class
{
T* _Buffer;
public:
template<size_t SIZE>
Class(T (&static_array)[SIZE])
{
_Buffer = (T*)malloc(sizeof(T) * SIZE);
memcpy(_Buffer, static_array, sizeof(T) * SIZE);
}
~Class()
{
if(_Buffer)
{
free(_Buffer);
_Buffer = NULL;
}
}
};
int main()
{
int int_array[32];
Class<int> c = Class<int>(int_array);
return 0;
}
Alternatively, if you hate to malloc / new, then you can create a size templated class instead. Though, I wouldn't really recommend it and the syntax is quite ugly.
#include <cstdio>
template<typename T, size_t SIZE>
class Class
{
private:
T _Array[sz];
public:
Class(T (&static_array)[SIZE])
{
memcpy(_Array, static_array, sizeof(T) * SIZE);
}
};
int main()
{
char int_array[32];
Class<char, sizeof(int_array)> c = Class<char, sizeof(int_array)>(int_array);
return 0;
}
Anyways, I hope this was helpful :)
I had the same problem and I solved it this way
class example
{
int *array;
example (int size)
{
array = new int[size];
}
}
Don't you understand there is not need to use vector, if one wants to use arrays it's a matter of efficiency, e.g. less space, no copy time (in such case if handled properly there is not even need to delete the array within a destructor), etc. wichever reasons one has.
the correct answer is: (quoted)
class Class
{
int* array;
Class(int x) : array(new int[x]) {};
};
Do not try to force one to use non optimal alternatives or you'll be confusing unexperienced programmers
Instead of using a raw array, why not use a vector instead.
class SomeType {
vector<int> v;
SomeType(size_t x): v(x) {}
};
Using a vector will give you automatic leak protection in the face of an exception and many other benefits over a raw array.
Like already suggested, vector is a good choice for most cases.
Alternatively, if dynamic memory allocation is to be avoided and the maximum size is known at compile time, a custom allocator can be used together with std::vector or a library like the embedded template library can be used.
See here: https://www.etlcpp.com/home.html
Example class:
#include <etl/vector.h>
class TestDummyClass {
public:
TestDummyClass(size_t vectorSize) {
if(vectorSize < MAX_SIZE) {
testVector.resize(vectorSize);
}
}
private:
static constexpr uint8_t MAX_SIZE = 20;
etl::vector<int, MAX_SIZE> testVector;
uint8_t dummyMember = 0;
};
You can't do it in C++ - use a std::vector instead:
#include <vector>
struct A {
std::vector <int> vec;
A( int size ) : vec( size ) {
}
};
Declare your array as a pointer. You can initialize it in the initializer list later through through new.
Better to use vector for unknown size.
You might want to look at this question as well on variable length arrays.