Initialising a 2D vector with values at declaration - c++

I'm currently working on a program which randomly generates items (e.g. weapons, armour etc.) and I want to make global constant vectors which hold all the names that could be given to the items. I want to have this 2D vector in a header file that's available to all my other classes (but not modifiable), so I need to initialise it at declaration.
I previously used the following:
static const std::string v[] =
{
"1.0", "1.1", "1.2", "null"
};
const std::vector<std::string> versions( v, v+sizeof( v)/sizeof( v[0]));
This worked for a 1D vector, however I want to use a 2D vector to store item names.
I have tried using the following however it means I don't have the member functions (such as size()):
static const std::string g_wn_a[] = { "Spear", "Lance", "Jouster" };
static const std::string g_wn_b[] = { "Sword", "Broadsword", "Sabre", "Katana" };
const std::string* g_weapon_names[] = { g_wn_a, g_wn_b };
I also don't want to use a class to store all the names because I feel it would be inefficient to have variables created to store all the names everytime I wanted to use them.
Does anyone know how I can solve my problem?

You could use a class with const static members. This way, your class would just behave like a namespace and you wouldn't have to create an instance of the name-holding class to use the names.
struct MyNames {
// const static things
const static string myweapon = "Katana"
};
string s = MyNames::myweapon; // s = "Katana"

This is C++, so the most common way to do this is to write a class that does this in its constructor, and then create a const object of that class. Your class would then provide various member functions to query the various items it maintains.
As a bonus, this will make it easier for the rest of your code to use the various items.

Related

What is the best way to initialize a more complex class construct with many unchangeable members in c++

I'm currently designing classes that should represent a chaotic storage system.
Lets say we have slots in rows and columns with certain properties.
So the slots have different restrictions in min/max height, width, length, weight and some more that come from a parameter file.
Also the Slots have a max total weight that must be checked before a new parcel gets added to that slot. And also the max weight that a row of slots can hold is lower than the sum of the max weights of the single slots. So for example each individual slot might be able to hold 50kg but the row of 10 slots must not exceed 200kg, so it is not allowed to fill every slot by 100%. The same is true for the Columns where the maximum weight is lower than the sum of the individual weights of the single rows. The row_id and column_id are atrificial numbers for adressing the slot in the physical system with barcodes or whatever that get read for positioning.
As all this parameters do not change over the lifetime of the program, my intention was to design the classes in a way that this properties are readable by getter functions but there should not be any setter functions (maybe not even private ones) in the object o the values cannot be changed by accident.
There is one class/function that reads the config-file and generates the data structure for the rows and columns with the slots. This function should be able to read the config and create objects for every column holding a row of slots and pass all the values from the config down to the slot.
Later when the program is running I also need some way to search for the best matching slot to add the next parcel or for searching parcels and unload them in a certain sequence.
So the (simplfied) basic structure of the classes would be like this:
Class Parcel {
int width;
int height;
int length;
int weight;
}
Class Slot {
vector<Parcel> parcel;
int min_width;
int max_width;
int min_height;
int max_height;
int min_length;
int max_length;
int max_total_weight;
int act_total_weight;
int total_length;
int free_length;
}
Class Row {
vector<Slot> slot;
int row_id;
int max_total_weight;
int act_total_weight;
}
Class Column {
vector<Row> row;
int column_id;
int max_total_weight;
int act_total_weight;
}
Class Storage {
vector<Column> column;
}
So here are my thoughts about how to initialize the data structure:
First possibility would be to pass all the properties in the constructor(s) of the classes, but then the constructors has some huge parameter lists specially for the Slot class that has a lot of properties.
Second thing that came to my mind (and currently my fafourite way to go) is to use config-data-structures that hold all the parameters. This parameter-objects get filled by the config-function and passed to the constructor when initializing the class. Then it also may be useful to use the parameter class as such and not having all the parameters defined in the storage class once more.
Third way is to use private setter and public getter and make the config class friends with the data structure classes to be able to access the setter functions (but i would prefer to have no setters at all in the final storage structure classes.
Fourth way that i was thinking off, was to derive child classes from the structure classes that hold the setter functions (and also some other logic needed for creating the data structure) so the child has no own variables but only additional functions. So the child class is used to fill the properties but the base class gets added to the data structure vector.
I also want to use Factory pattern to initialize the data structure because the objects have often similar or only slightly different properties. So with the second aproach after creating one row of slots I would maybe want to change the max weight of the slots in that row. Therefore I would need to change the setting in the factory and the factory then fills the parameter data structure differently and passes it to the Slot class. Or is it better to pass the data structure to the factory directly and the factory assigns it but then i think this is not what the factory pattern is meant to be.
I don't know if this is a good aproach or which of the above is best practice.
Or am I missing something and there is a way more convenient solution or this?
Thank you (and sorry if the question is maybe not the way it should be)
When constructing your classes as you describe it you can have a look at the creational design patterns.
Your second proposed solution is almost a builder design pattern. This will help you to construct the Slot e.g. piecewise.
As an example:
#include <iostream>
class Slot {
public:
int GetMinWidth() const { return min_width_; };
int GetMaxWidth() const { return max_width_; };
// Builder class
class SlotBuilder {
public:
SlotBuilder& SetMinWidth(int min_width) {
min_width_ = min_width;
return *this;
}
SlotBuilder& SetMaxWidth(int max_width) {
max_width_ = max_width;
return *this;
}
Slot Build() {
return Slot(min_width_, max_width_);
}
private:
int min_width_{/* you can add default value here*/};
int max_width_{/* you can add default value here*/};
};
// This is optional, but creates a neat interface
static SlotBuilder Create() {
static SlotBuilder slot_builder;
return slot_builder;
}
private:
// Make constructor private to restrict access and force the use of the builder
Slot(int min_width, int max_width) : min_width_(min_width), max_width_(max_width) {}
const int min_width_;
const int max_width_;
// .
// .
// Continue with your const attributes
};
int main() {
// Create the slot with the builder
Slot slot = Slot::Create()
.SetMinWidth(10)
.SetMaxWidth(20)
.Build();
std::cout << slot.GetMinWidth() << ", " << slot.GetMaxWidth();
return 0;
}
You can see the example working here
For having different types that are almost the same a Prototype pattern could work if you want to "clone" a class or in your case a Factory pattern could do the job.
There is never an ideal solution or that one pattern that solves it all, so I can't give you a definitive answer, but here are some collected thoughts:
Default values
Primitive types like int don't have a default value, so make sure you give them one explicitly:
struct Parcel {
int width{};
int height = 0;
int length = {};
int weight{};
}
All those different versions above are equivalent, but you really should use one of them. Otherwise you will probably run into UB down the line.
Const correctness
One thing that I love about C++ and that I dearly miss in languages like C# is const correctness. If you want an object to be immutable, declare it as const. To prevent changes to your objects, either instantiate the object as a const:
const Parcel x;
x.width = 10; // compiler error
or make the members of your classes const:
struct Parcel {
const int width{};
const int height{};
const int length{};
const int weight{};
};
Parcel x;
x.width = 10; // compiler error
Aggregate initialization
If you keep your types simple enough you can initialize the class members with curly braces directly:
const Parcel x { 1, 2, 3, 4 };
In C++ 20, you can also name the members, so this code is equivalent to the line above:
const Parcel x { .width = 1, .height = 2, .length = 3, .weight = 4 };
Note that this can bite you later though if you have to deal with ABI stability and versioning. In that case you are better off using getter and setter functions, because that allows you to still change the data layout of your members.
I have to think about design patterns a bit more. I'll update this post if something useful comes out of it.

Declare a "list" of constant in a class

I would like to create a list of constant within my class but I don't know how tto do it properly.
First I tried to but it in an Enum like that:
class CMyClass{
public:
enum EKeyword
{
E_PARAM1 = "myString1",
E_PARAM2 = "myString2",
...
};
but it seems that it is not possible (-> error C2057: expected constant expression)
I know that I could just declare one by one each of my constant with a #define or using "static const ..." declaration but I like the use of : EKeyword.E_PARAM1 to get my string and I don't want to set those constants global.
Any recommandations ?
You cannot make an enum with a string representation in c++. You will need a list of strings. If you wan't to force them to be referenced inside a structure (like an enum class) add them to a struct:
class CMyClass {
public:
struct EKeyword {
static constexpr char const* PARAM_1 = "myString1";
...
private:
EKeyword(); // Disables the ability to construct an EKeyword struct.
};
...
Then use within the class will be like:
EKeyword::PARAM_1
and outside the class will be:
CMyClass::EKeyword::PARAM_1
If you are limited to c++03 you will need to create the string values in a cpp file:
// .hpp
class CMyClass {
...
struct EKeyword {
static char const* PARAM_1;
...
// .cpp
char const* CMyClass::EKeyword::PARAM_1 = "myString1";
Here is a live example.
Following this comment from the asker:
I'm creating a list of keyword that I will looking for in a file and
then exchange the keyword with its value. ex: find the keyword
"$temperature" -> replace the word with "28°C"
The approach you are suggesting of using named variables, or an enum will be inappropriate for this since C++ has no reflection and variable names are not accessible from the code. What you want is a map - possibly std::map<std::string, std::string>, although higher performance options might be necessary depending on the use case - from the values you want to find to the values you want to replace them with.
The best way to do this would be to read in a file containing the replacement values because then you can modify the replacement values without modifying the code and have a more general solution, but you can otherwise use C++11's unified initialisation lists to populate the map in your code, or perhaps populate them one by one in, for example, a constructor, if unified initialisation isn't suitable for your needs or for some reason C++11 is unavailable to you.
You can then scan through the file finding strings you want to replace and replacing them with the listed replacement. Be careful though, what will you do about overlapping replacement? Do you only check whole words, etc?

Char array initialisation in class

I am trying to unit test a C++ application that I am building and I'm having an issue initializing the array when used in a class. I've tried alot of different methods of loading this information, the only ones that work are inefficient / not suitable.
Here is the hex array that I have (randomised the parts)
0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10
And header file for my unit test:
class MessageParsingTest : public CPPUNIT_NS::TestFixture {
CPPUNIT_TEST_SUITE(MessageParsingTest);
CPPUNIT_TEST(testIdentifyFirstMessageType);
CPPUNIT_TEST_SUITE_END();
public:
MessageParsingTest();
virtual ~MessageParsingTest();
void setUp();
void tearDown();
private:
void testIdentifyFirstMessageType();
void testIdentifySecondMessageType();
// data members for the hex array
unsigned char firstMessage[1500];
};
Then in my test case setUp function;
void MessageParsingTest::setUp() {
firstMessage = {0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10};
}
That it my latest failed attempt, it says its not valid during compilcation, as I expected, but at this point I was trying anything.
I've also tried things like (all in setUp function)
firstMessage << "\0x24\0x54\0x3b\0x72\0x8b\0x03\0x24\0x29\0x23\0x43\0x66\0x22\0x53\0x41\0x11\0x62\0x10";
firstMessage[1500] = "\0x24\0x54\0x3b\0x72\0x8b\0x03\0x24\0x29\0x23\0x43\0x66\0x22\0x53\0x41\0x11\0x62\0x10";
and a few other crazy ways, Does anyone know the proper way to load this data? the only way I've had it working so far is with either no data member declaration and straight up defining it and initializing in one line (but then I cant access in the test cases) or doing it one by one like firstMessage[0] = 0x24; etc.
I understand that there will be a simple, proper way of doing this and considering what the application actually does, this part should be the easiest.
You have few options:
Initialize arrays in constructor MesssageParsingTest using syntax : firstMessage{0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10}
in initializer list.
Create static const array containing your message, and either copy it to member variable using memcpy, or use static member and get rid of firstMessage member variable.
Declare const static member in .h inside class definition:
static const unsigned char kFirstMessage[];
and define + initialize it in .ccp
const unsigned char MessageParsingTest::kFirstMessage[] = "\0x24\0x54\0x3b\0x72\0x8b\0x03\0x24\0x29\0x23\0x43\0x66\0x22\0x53\0x41\0x11\0x62\0x10";
I would prefer static const member if you do not intend to modify this array later, since it makes the intention cleaner.
Here is one way to do it.
void MessageParsingTest::setUp()
{
unsigned char x[] = {0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10};
::memcpy(firstMessage, x, sizeof(x));
}
If you are using C++11, you can also initialize the firstMessage in the class member initialization list as
MessageParsingTest::MessageParsingTest() :
firstMessage{0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10},
...
You can use a temporary buffer and then copy into you member as this:
void MessageParsingTest::setUp() {
unsigned char tmp[1500] = {0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10};
memcpy(firstMessage, tmp, 1500);
}

C++ struct with template in vector

I'm making a text adventure game in C++. This is the struct for an object in that game (something the user can pick up and put in the inventory)
template <int N>
struct Object
{
static const int length = N;
string names[N];
string description;
};
Examples of objects:
Object<2> flower = { {"flower", "the flower"}, "A strange looking flower"};
Object<3> book = { { "the book", "book", "recipe book" }, "The world's finest cocktail recipes now all in one easy to use companion." };
The multiple names are synonyms for the command parser, so the user can input "pick up book" or "pick up recipe book", which in both cases picks up the object book.
Now I'd like to create a vector inventory to store all the elements in the inventory.
vector<Object> inventory;
Now, off course, this gives me a compiler error, because it expects something like this:
vector<Object<5>> inventory;
However, some objects have more names than others, is something like this possible and if so, how?
vector<Object<N>> inventory;
All your different Object<N> classes are different types with different sizes. You can't put them in a homogenous container.
You would need some base class or base interface, and store pointers in the vector, relying on virtual dispatch and polymorphism when you pull the elements out. This would make your container of Objects a heterogenous container.
Alternatively, and preferably, drop the template and store the names in a member container:
struct Object
{
set<string> names;
string description;
};
vector<Object> easy;
PS. I don't consider Object to be a good name for any class. CompuChip's suggestion of InventoryItem makes more sense.
A vector needs to know the size of the objects it contains, so obviously it cannot allow varying template instances inside (sizeof(Object<N+X>) > sizeof(Object<N>)).
Remove the templated array from the main Object struct, and replace it with a common vector or list or string objects instead, and your problem is solved.
Derive Object from BaseObject, and form a vector of smart pointers to BaseObject:
struct BaseObject
{
virtual ~BaseObject() = default;
};
template<int N>
struct Object : public BaseObject
{
static const int length = N;
string names[N];
string description;
};
typedef shared_ptr<BaseObject> Objptr;
vector<Objptr> Inventory(1006);

read data in initialization list

At class instantiation, I would like to read data from a file and process it into a number of class objects. What I did so far (and works well) is
myData::myData(const std::string & file):
data1_(this->read(file)),
processedData1_(this->createProcessedData1_(data1_)),
processedData2_(this->createProcessedData2_(data1_)),
processedData3_(this->createProcessedData3_(data1_))
{
}
In a different class, the read() method creates more than one raw data object. In this case, I don't know how to pack things into the initializer list, so I'm doing something along the lines of
myData::myData(const std::string & file):
data1_(),
data2_(),
processedData1_(),
processedData2_(),
processedData3_()
{
this->read(file); // fills data1_, data2_
processedData1_ = this->createProcessedData1_(data1_, data2_);
processedData2_ = this->createProcessedData2_(data1_, data2_);
processedData3_ = this->createProcessedData3_(data1_, data2_);
}
What I don't like about this approach is that
the data is initalized twice: once (void) in the initializer list, once filled with actual content in the constructor; and that
I cannot mark any of the (processed) data objects as const.
Is there a way to organize the object creation such that it all happens in the initialization list?
You may think about splitting the data loading / processing in a factory-like static method that in turn constructs a myData instance (passing the processedData*_ values as constructor params).
This way you can keep the loading and processing separate from the class that may end up just storing the results and possibly provide further processing or accessors to parts of the data.
Could something like
class MyData {
public:
MyData(DataType processedData1, ...) : processedData1_(processedData1) ... { }
private:
const DataType processedData1_;
}
struct DataContainer {
DataType data1;
DataType data2;
}
DataContainer read(const std::string& file) { ... }
DataType createProcessedData1(DataType data) { ... }
...
// hands ownership to caller
MyData* LoadData(const std::string & file) {
DataContainer d = read(file);
return new MyData(createProcessedData1(d.data1), createProcessedData2(d.data2), ..)
}
work for you?
I'm assuming you don't need to keep state when loading and processing data. If this isn't the case you can make read and createProcessedData* members of a MyDataLoader class.
The only way to supply a value to a const member variable (without const cast or using mutable keyword) would be to provide it in the constructor initializer list. See this: How to initialize a const field in constructor.
If you prefer not to refrain to the 'ugly' casts or keywords and need your data to be be const (for example for use in const functions), I would go for a small myDataInitialiser class that would first read the data. Once data is read, you could pass the whole instance of initialiser to the constructor of your original myData class.