I want to create a constant (preferably static but not necessary) member variable in my class.
I want it to be a 3-dimensional array with each length size 2.
The purpose: store some data that is time consuming to recreate on each change, for combinations of 3 types of boolean choices, without having to do complicated testing on each change.
What I don't know how to do: how to initialize the 3D array.
This is what I am trying (based on cplusplus.com/forum/Multi-Dimensional Arrays):
class MyClass {
public: ...
~MyClass(); // will I need to destroy m_previewIcons to prevent memory leak ?
private: ...
static const QIcon m_previewIcons[2][2][2]; // the array I need
static QIcon*** initializePreviewIcons(); // what type of return ?
};
const QIcon MyClass::m_previewIcons[2][2][2] = MyClass::initializePreviewIcons();
QIcon ***MyClass ::initializePreviewIcons()
{
QIcon ***iconArray = 0;
// Allocate memory
iconArray = new QIcon**[2];
for (int i = 0; i < 2; ++i)
{
iconArray[i] = new QIcon*[2];
for (int j = 0; j < 2; ++j)
iconArray[i][j] = new QIcon[2];
// is this even right ? it seems to me I miss out on a dimension ?
}
// Assign values
iconArray[0][0][0] = QIcon(":/image1.png");
iconArray[0][0][1] = QIcon(":/image2.png"); ...
iconArray[1][1][1] = QIcon(":/image8.png");
return iconArray;
}
As far as I got...
error: conversion from 'QIcon***' to non-scalar type 'QIcon' requested
How can I get this initialization to work ?
Note - QIcon is a built-in class in Qt, which is what I use (any class would be the same).
No C++ 11 though.
I could have used vectors I suppose but I wanted less overhead.
Edit: I have just thought of an alternate way to do it... give up on the 3D array, use simple 1D array and build an int for index using the booleans bit shifted. may be more effective.
But I would still want to know how to initialize a 3D array.
You're creating a a static array, and then trying to allocate its memory dynamically, which isn't necessary - the memory is already there by virtue of your declaration static const QIcon m_previewIcons[2][2][2];
You should initialize your 3d array using list initialization, a la this answer.
Heres an example with a non-POD type, std::string:
#include <string>
class MyClass {
public:
static const std::string m_previewIcons[2][2][2];
};
const std::string MyClass::m_previewIcons[2][2][2] = {
{ {":/image1.png",":/image2.png"},
{":/image3.png",":/image4.png"} },
{ {":/image5.png",":/image6.png"},
{":/image7.png",":/image8.png"} }
};
int main()
{
MyClass mc;
printf("%s\n", mc.m_previewIcons[0][0][0].c_str());
}
The problem is that C++ provides no class initialization: only static initializers or instance constructor.
But here, it is easy, because the construction of the elements of the array is straightforward, so you could use:
class MyClass {
public: ...
~MyClass(); // will I need to destroy m_previewIcons to prevent memory leak ?
private: ...
static const QIcon m_previewIcons[2][2][2]; // the array I need
};
const QIcon MyClass::m_previewIcons[2][2][2] = {
QIcon(":/image1.png"),
QIcon(":/image2.png"),
...,
QIcon(":/image8.png") };
As m_previewIcons has static linkage, its duration is the whole program so you have neither to provide storage for it nor to release it. Said differently, do not destroy it from the destructor.
Related
I have a SPI test class which I am trying to make flexible specially for user to be able to change\set the size of the Tx and Rx buffers which are private members of SpiTest class.
I have tried few ways by const_cast etc., but compiler keeps giving different sort of errors each time.
What would be best way to make my SpiTest class flexible enough to provide user a function which can be used to change the size of the buffer or may be just set a size of the buffer once but by client/user. Even once after creating test object to initialize size will be good enough.
Any ideas will be highly appreciated.
I have tried
Using Tx_size member as static then it complains about constness
1b- making Tx_size const complains about setting size is not possible using SetTxSize() method.
Initialising it in constructor not advantage.
Applying const_cast but that is only applicable to change pointer types consts
This is my class:
class SPITest
{
public:
SPITest();
~SPITest() = default;
uint8_t* GetTxBuf(void)
{
return &TX_m[0];
}
uint8_t* GetRxBuf(void)
{
return &RX_m[0];
}
uint8_t GetTxSize(void)
{
return Tx_Size;
}
void SetTxSize(uint8_t size)
{
Tx_Size= (size);
}
private:
static uint8_t Tx_Size = 6;
uint8_t TX_m[Tx_Size];
uint8_t RX_m[Tx_Size];
};
Errors are as follows:
Error[Pe1592]: a member with an in-class initializer must be const
Error[Pe028]: expression must have a constant value
Use a vector
Use a std::vector instead - a vector is a dynamic array.
Your class then becomes:
#include <vector>
class SPITest
{
public:
//...
void SetTxSize(size_t size)
{
TX_m.resize(size);
}
private:
std::vector<uint8_t> TX_m;
std::vector<uint8_t> RX_m;
};
I want to define an array of structs, but this is not working because it has a const field without default constructor.
Struct is part of an SDK and looks like following:
struct SParametricParamDef
{
const TXString fUniversalName;
SResString fLocalizedName;
const TXString fDefaultImperial;
const TXString fDefaultMetric;
EFieldStyle fFieldStyle;
short fChoicesChcID;
};
TXString does not have a default constructor. So following is failing:
SParametricParamDef *arrParams = new SParametricParamDef[size]; // <= throws compile time exception
for (int i = 0; i < size; i++)
{
arrParams[i] = params[i].def; // <= also throws an exception, because operator = is not available
}
Is there some way to solve this? I need an SParametricParamDef* as a result, because this array is used in the SDK again...
Info
In an old SDK version, const TXSTring was const char* and back then I did not have problems... Now I need to adjust my code to work with the new structures...
The error you get is not primarily about operator = but about the fact that you default-constructed an object with const members. This will render them immutable and any attempt to modify them, as you are trying in the loop, must fail.
Fortunately, you can use emplace_back to initialize the SParametricParamDef objects right inside the vector without taking the indirection of default-construction and assignment:
std::vector<SParametricParamDef> arrParams;
for(std::size_t n = 0; n < size; ++n) {
arrParams.emplace_back(params[n].def);
}
This should minimize the amount of copying and comes without the need to modify the struct definition.
The compiler is telling you that you are asking for a TXString to be created without directing how it can be initialised. It is difficult to know how to address the problem of creating a TXString object since you haven't given a list of the constructors for the class, but as it stands a change would need to be made to the code you've given. Some ways of solving this are as follows:
The most obvious is to add a default constructor for SParametricParamDef which initialises the TXString objects:
struct SParametricParamDef
{
SParametricParamDef() : fUniversalName(...), ... {}
...
Another approach, given that the variables are const might be to make them const static
Say, for simplicity's sake, that the TXString object was as follows:
struct TXString{
TXString(char a) : _a(a) {}
char _a;
};
You could then change your declaration of SParametricParamDef to:
struct SParametricParamDef
{
const static TXString fUniversalName;
...
and then define fUniversalName in your implementation file as follows:
const TXString SParametricParamDef::fUniversalName('D');
Another way might be to wrap a TXString object in another object that does have a default constructor:
struct TXStringWrapper {
TXStringWrapper() : _s(...) {} // [1]
const TXString& get() { return _s; }
private:
TXString _s;
}
At [1], you create the TXString in whatever specific, non-default way that you care.
That looks like an example for using a placement new:
SParametricParamDef *arrParams = (SParametricParamDef *) new char[size * sizeof(*arrParams)];
for (int i = 0; i < size; i++)
{
// constructs an object in a pre-allocated memory
new(arrParams+1) SParametricParamDef(params[i].def);
}
You should explicitely call a destructor if it is not trivial before freeing the array:
for (int i = 0; i < size; i++)
{
~SParametricParamDef(arrParams+1);
}
delete[] ((char *) arrParams);
This is rather old fashioned because it mimics the initialization of structs in C, but it is the only way I know to build an array of objects that only have non trivial constructors (AFAIK, the std::vector way requires copyable or movable objects)
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.
C++ and Class
I have a class called “Sprite”, when this is initialized it takes a bool variable:
// constructor
Sprite::Sprite(bool type)
{
// set stuff
}
// two Sprites of different types
Sprite Hero(1)
Sprite Enemy(0)
Q. How do I initialize an array of 100 Sprites of type 0?
Sprite Enemies[100] ?
My suggestion is that you use a std::vector, and then use the constructor taking a value argument.
Like
std::vector<Sprite> Enemies(100, Sprite(false));
You might need proper copy-constructor and copy-assignment operators defined for Sprite for it to work.
If you don't have vectors (or std::array which might be better in your case), then you have to declare the array as a normal array, and then use a loop to initialize each entry:
Sprite Enemies[100];
for (size_t i = 0; i < 100; ++i)
Enemies[i].set(false);
You can use a default constructor, that will simply default to the 0 value like this:
//default constructor
Sprite::Sprite()
{
//set to false
}
Sprite::Sprite(bool type)
{
// set to type
}
Now
Sprite Enemies[100]
will work
Or with a little less code use a default value in the constructor like so:
Sprite::Sprite(bool type=false)
{
//set to type
{
Unless I'm wrong, you cannot directly use constructor with parameters for object arrays. One solution is using a std::vector :
std::vector<Sprite> Ennemies(100, Sprite(false));
std::vector<Sprite> Ennemies(100, {false}); // C++11 style
If you really want C-style array, you can get it, by an example :
Sprite* pEnnemies = &Ennemies.front();
One other solution is using the new C++11 container std::array which is only a C-Style array in STL syntax :
std::array<Sprite, 100> Ennemies(Sprite(false));
When creating an array of classes, they must be created by the default constructor.
You could add a default value "= false" for your type parameter, and then the code would work. It's not very flexible though, as you might want an array of the other type.
Another way is to allow your sprite to be reset after construction with a different type. After creating your array of blank sprites, call reset(type) on them in a for loop.
If you really need to use a non-default constructor on your elements, use std::vector. There are two ways to do it.
std::vector<Sprite> Enemies;
Enemies.reserve(100);
for (int i = 0; i < 100; i++)
{
Enemies.push_back(Sprite(0));
}
or
std::vector<Sprite> Enemies(100, Sprite(0));
For the sake of completeness, there is one last method using placement-new:
unsigned char data[sizeof(Sprite) * 100];
Sprite* ptr = reinterpret_cast<Sprite*>(&data[0]);
Sprite* end = ptr + 100;
for (; ptr != end; ++ptr)
new (ptr) Sprite(0);
This is pretty much what the other answers, that don't rely on the copy-constructor use internally.
If Sprite has a non-trivial destructor you will have to call it explicitly using another loop at the end of data's lifetime:
Sprite* ptr = reinterpret_cast<Sprite*>(&data[0]);
Sprite* end = ptr + 100;
for (; ptr != end; ++ptr)
ptr->~Sprite();
Many thanks all for taking a look, after reading comments I've found this works, overloading the constructor:
class Sprite
{
public:
Sprite();
Sprite(bool type);
void Move();
private:
unsigned int x, y, Ammo;
bool Alive;
bool Type;
};
// constructor
Sprite::Sprite()
{
Alive = true;
Type = 0;
Ammo = 25;
x = random(0, 82);
y = random(0, 20);
}
Sprite::Sprite(bool type)
{
Alive = true;
Type = 1;
Ammo = 25;
x = 20; // get x from btn press
y = 10; // get y from btn press
}
Sprite Hero(1);
Sprite Enemies[100];
Use a default argument:
Sprite::Sprite(bool type=false) : mymember(type)
{}
and then when you declare:
Sprite Enemies[100];
it will call the default ctor for all 100 elements.
You should learn about member-initializer lists, the proper way to write a constructor in C++ is:
Sprite(bool type=false); // declaration
...
Sprite::Sprite(bool type) : // definition
x(random(0, 82)),
y(random(0, 20)),
Ammo(25),
Alive(true),
Type(type)
{}
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.