Optimizing storage space for classes in C++ in an Arduino library - c++

I'm writing an Arduino library to wrap the pin functions (digitalRead, digitalWrite, analogRead, etc.). For example, I have a RegularPin class which is a passthrough and an InvertedPin class which inverts the pin logic. This is useful when going from the breadbord with LEDs to a relay board which inverts the circuit logic. I just have to swap classes.
I also have a DebouncedPin class for buttons which checks the user presses or releases long enough for the button to be really pressed/released.
Example for analog pins:
// AnalogInPin ------------------------------
class AnalogInPin
{
public:
virtual int read()=0;
virtual int getNo()=0;
};
// AnalogRegInPin ---------------------------
template<int pinNo>
class AnalogRegInPin : public AnalogInPin
{
public:
AnalogRegInPin();
int read();
int getNo(){return pinNo;}
};
template<int pinNo>
int AnalogRegInPin<pinNo>::read()
{
return analogRead(pinNo);
}
template<int pinNo>
AnalogRegInPin<pinNo>::AnalogRegInPin()
{
pinMode(pinNo, INPUT);
}
As you can see, I put the pin number in the template declaration because it is not to be changed at run time and I do not want the pin number to use memory when I allocate a pin object, just like in vanilla arduino C code. I know classes can not be of size zero but read on. Next, I want to write an "AveragedPin" class which will automatically read the selected pin several times and I would like to stack my templated classes like this :
AveragedPin<cAnalogRegInPin<A0>, UPDATE_ON_READ|RESET_ON_READ> ava0;
or even :
RangeCorrectedPin<AveragedPin<cAnalogRegInPin<A0>,
UPDATE_ON_READ|RESET_ON_READ,RAW_MIN,RAW_MAX,TARGET_RANGE> rcava0;
For the time being, I declared the nested pin as a private member because it is not allowed to use a class object in the template declaration. But then, each layer of nesting uselessly eats several bytes on the stack.
I know I could use references in the template declaration, but I don't quite understand how that works/should be used. My problem looks like empty member optimization, but it doesn't seem to apply here.
I feel this is more a C++ question than an arduino one and I'm not a C++ expert. I guess this touches the more advanced parts of C++. Maybe what I want is not possible, or only with recent C++ (20?) revisions.
Below is the code for the FixedRangeCorrectedPin class.
template <class P, int rawMin, int rawMax, int targetRange>
class FixedRangeCorrectedPin : public AnalogInPin
{
public:
int read();
int getNo(){return pin.getNo();}
private:
P pin;
};
template <class P, int rawMin, int rawMax, int targetRange>
int FixedRangeCorrectedPin<P, rawMin, rawMax, targetRange>::read()
{
int rawRange = rawMax - rawMin;
long int result = pin.read() - rawMin;
if (result < 0) result = 0;
result = result * targetRange / rawRange;
if (result > targetRange) result = targetRange;
return result;
}
My problem is that I would like to remove the 'P pin' class member and replace it in the template declaration like in template <AnalogInPin pin,int rawMin,int rawMax,int targetRange> because which pin is involved here is completely known at compile time.

As you can see, I put the pin number in the template declaration because it is not to be changed at run time and I do not want the pin number to use memory when I allocate a pin object, just like in vanilla arduino C code.
OK, if the pin number is a compile-time constant as it usually is for Arduino, this bit is fine.
However, making the AnalogInPin base class abstract (ie, adding virtual methods) will in practice use at least as much space per object as you saved by not storing the pin as an integer.
The details are implementation-specific, but runtime polymorphism requires some way of figuring out, for a given derived-class object pointed to by an AnalogInPin*, which version of the virtual methods to call, and that requires storage in each object of derived type. (You can verify that this is true buy just checking sizeof(AnalogInPin) and comparing to sizeof an otherwise identical class with no virtual methods.
I know classes can not be of size zero but ...
There's an special case for base classes with no data members that allows them to take no extra size (an instance of the most-derived type must still occupy at least one byte). It's called the empty base class optimization.
For the time being, I declared the nested pin as a private member because it is not allowed to use a class object in the template declaration. But then, each layer of nesting uselessly eats several bytes on the stack.
We can flatten the whole thing (and ideally remove the abstract base too, unless you have non-templated code that needs it):
template <int PIN, template <int> class BASE>
struct AveragedPin: public BASE<PIN>
{
int read() override { /* call BASE<PIN>::read() several times */ }
int getNo() override { return PIN; }
};
However, note that we could just use the inherited getNo, and then don't really use PIN at all. So instead of declaring an averaged pin instance as AveragedPin<MY_PIN, AnalogInPin> myAveragedPin;, we could change the definition to
template <class BASE>
struct AveragedPin: public BASE
{
int read() override { /* call BASE::read() several times */ }
using BASE::getNo; // not really required unless it is hidden
};
and declare an instance as AveragedPin<AnalogInPin<MY_PIN>> myAveragedPin;.
The range-corrected pin can be similar but with extra template parameters for the flags and min/max bounds, if they're known at compile time.
Similarly, the FixedRangeCorrectPin added to your question, doesn't need to derive from AnalogInPin and then also store a different pin type. In fact, it can just inherit the base class
template <class P,int rawMin,int rawMax,int targetRange>
struct FixedRangeCorrectedPin : public P
{
int read(); // calls P::read()
// inherit getNo again
};
again, declaring an instance like FixedRangeCorrectPin<AnalogInPin<MY_PIN>, RMIN, RMAX, TARGET> myFixedPin;
Edit Example of an average over a variable number of pins, with no storage overhead, assuming we changed the virtual methods to static:
template <class... PINS>
struct AveragedPins
{
static int read()
{
return (PINS::read() + ...) / sizeof...(PINS);
}
};
This doesn't care what sort of pin the argument is, so long as it has a static read method. You can stack it however you like:
using a1 = FixedRangeCorrectedPin<A_1, 0, 255, 128>;
using a2 = AnalogInPin<A_2>;
using a3 = AnalogInPin<A_3>;
using a4 = AnalogInPin<A_4>;
using a34 = AveragedPins<a3, a4>;
using all = AveragedPins<a1, a2, a34>;
// now a34::read() = (a3::read() + a4::read())/2
// and all::read() = (a1::read() + a2::read() + a34::read())/3
and note that all of those are just type definitions: we're not allocating even one byte for any objects.
One more note: I noticed that I'm using the same CLASS::method() syntax in two slightly different ways.
in the first examples above, which use inheritance, BASE::read() is a de-virtualized instance method call.
That is, we're calling BASE's version of the read method on this object. You could also write this->BASE::read().
It's de-virtualized because although the base-class method is virtual, we know at compile time the right override to call, so virtual dispatch isn't necessary.
in the final examples, where we stopped using inheritance and made the methods static, PIN::read() has no this and there is no object at all.
This is the most similar in principle to calling a free C function, although we're getting the compiler to generate a new instance of it for each different PIN value (and then expecting it to inline the call anyway).

Related

How to declare a class member that may be one of two classes

I am working with a project that is largely not of my creation, but am tasked with adding in some functionality to it. Currently, there is a device class that has a member variable that is responsible for storing information about a storage location, setup like this:
device.hpp
class device {
public:
// Stuff
private:
// Stuff
StorageInfo storage_info_;
// Even more stuff
}
StorageInfo.hpp
class StorageInfo {
public:
void initializeStorage();
void updateStorageInfo();
int popLocation();
int peakLocation();
uint16_t totalSize();
uint16_t remainingSize();
// More declarations here
private:
//Even more stuff here
}
I am tasked with implementing a different storage option so that the two can be switched between. The information functions that this new storage option has would be the same as the initial storage option, but the implementation in retrieving that information is vastly different. In order to keep things clean and make it easier to maintain this application for years to come, they really need to be defined in two different files. However, this creates an issue inside of device.cpp, and in every single other file that calls the StorageInfo class. If I create two separate member variables, one for each type of storage, then not only will I need to insert a million different ifelse statements, but I have the potential to run into initialization issues in the constructors. What I would instead like to do is have one member variable that has the potential to hold either storage option class. Something like this:
StorageInfoA.hpp
class StorageInfoA: StorageInfo {
public:
void initializeStorage();
void updateStorageInfo();
int popLocation();
int peakLocation();
uint16_t totalSize();
uint16_t remainingSize();
// More declarations here
private:
//Even more stuff here
}
StorageInfoB.hpp
class StorageInfoB: StorageInfo {
public:
void initializeStorage();
void updateStorageInfo();
int popLocation();
int peakLocation();
uint16_t totalSize();
uint16_t remainingSize();
// More declarations here
private:
//Even more stuff here
}
device.hpp
class device {
public:
// Stuff
private:
// Stuff
StorageInfo storage_info_;
// Even more stuff
}
device.cpp
//Somewhere in the constructor of device.cpp
if(save_to_cache){
storage_info_ = StorageInfoA();
} else {
storage_info_ = StorageInfoB();
}
// Then, these types of calls would return the correct implementation without further ifelse calls
storage_info_.updateStorageInfo();
However, I know that cpp absolutely hates anything with dynamic typing, so I don't really know how to implement this. Is this kind of thing even possible? If not, does anyone know of a similar way to implement this that does work with cpp's typing rules?
You are on the right track, but you have to learn how to use polymorphism. In your example, you need the following fixes:
In the base class, make all functions virtual, and add a virtual
destructor:
class StorageInfo {
public:
virtual ~StorageInfo(){}
virtual void initializeStorage();
//...
};
Make your inheritance public:
class StorageInfoA: public StorageInfo {
Instead of holding StorageInfo by value, hold it in a smart pointer:
class device {
private:
std::unique_ptr<StorageInfo> storage_info_;
};
device constructor will look like
//Somewhere in the constructor of device.cpp
if(save_to_cache){
storage_info_ = std::make_unique<StorageInfoA>();
} else {
storage_info_ = std::make_unique<StorageInfoB>();
}
Finally, you will use it like an ordinary pointer:
storage_info_->updateStorageInfo();

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.

Pointer to function from another pointer

I'm new to c++ and I'm trying to make a generic switch (i.e. the device, not the C++ statement) that could be used to blink lights, turn beeps on and off, etc, in my Arduino project.
I could create a switchable interface and implement that in the classes that I want to "switch". But since I'm doing it as study purposes and I saw the pointer-to-functions ability in C++ (that is new to me since I come from C# and Java), I tough it would be a good opportunity to give it a try...
The problem is that I can pass the function in my code only if it's a local function but it won't work if I try to pass a function from another object like a led for example.
Some code to illustrate the problem. This is the switch.cpp, it recieves the On and Off functions in it's constructor and it has a update method that is called inside the loop method in the Arduino ino main class:
auto_switch.cpp
using switch_function = void(*)();
auto_switch::auto_switch(const switch_function on_function, const switch_function off_function, const int max_speed_count)
{
//sets all variables...
}
void auto_switch::update(const unsigned long millis)
{
//turn switch on and off...
}
And this is my ino file
ino file
#include <Arduino.h>
#include "led.h"
#include "auto_switch.h"
led* main_led;
auto_switch* led_switch;
int slow_speed;
//ugly code
void turn_led_on()
{
main_led->turn_on();
}
//ugly code
void turn_led_off()
{
main_led->turn_off();
}
void setup() {
main_led = new led(2, 3, 4, true, color::white);
//ugly code
led_switch = new auto_switch(turn_led_on, turn_led_off, 3);
slow_speed = led_switch->add_speed(100, 100, 3, 1000);
led_switch->set_active_speed(slow_speed);
led_switch->turn_on();
}
void loop() {
led_switch->update(millis());
}
It works but I had to make a local function (turn_led_on and turn_led_off) to be able to assign the inner functions as a parameter to the auto_switch constructor, the parts that I've wrote //ugly code
I wanted to do something like this, without the glue code in between:
//doesn't work
led_switch = new auto_switch(main_led->turn_on, main_led->turn_off, 3);
Is it possible? I've read something about static pointer to function and some std functions that help with that, if I get it right the glue code is necessary in this case so that the compiler can know where the functions are coming from I guess (from which object), but since the functions I need to call cannot be static I've discarded this option, and the std functions I believe it can't be used with the Arduino or could but shouldn't for performance limitations...
Anyway, does it make sense, can it be done using pointer to functions or should I create a interface or something different?
Before deciding how to do it, the qquestion is what do you want to do and why. Because, maybe there are better alternatives using simple C++ idioms.
Option 1: specialization with polymorphism
Do you want to specialize some functions of your switch, so instead of calling the function of the auto_switch you'd call dome more specialized ones ?
In this case you wouldn't do:
//doesn't work
led_switch = new auto_switch(main_led->turn_on, main_led->turn_off, 3);
but instead you would rely on polymorphism with virtual functions in the base class:
class auto_switch {
...
virtual void turn_on();
virtual void turn_off();
...
};
and write a specialized class for the leds:
class led_witch : public auto_switch {
...
void turn_on() override;
void turn_off() override;
...
};
In fact, the compiler will generate some function pointers behind the scene, but you don't have to care:
auto_switch s1=new auto_switch(...);
auto_switch s2=new led_switch(...); // no problem !!
s1->turn_on(); // calls auto_switch::turn_on()
s2->turn_on(); // calls led_switch::turn_on() since the real type of s2 is led_switch
But event if each object's behavior is dynamic on the the base of the real class of the object, the objects of the same class share a behavior that was predefined at compile time. If this is not ok, go to the next option.
Option 2: the member function pointer
The functions of another objects can only be invoked with that object at hand. So having a function pointer to a led function is not sufficient: you also need to know on which led it shall be applied.
This is why member function pointers are different and somewhat constraint: you can only invoke functions of class of your member function pointer. If polymorphism is sufficient (i.e. if derived class has a different implementation of a function already foreseen in the base classe) then you are lucky. If you want to use a function that only exists in the derived class and not in the base class, it won't compile.
Here a simplified version of auto_swith: I provide a function, but allso a pointer to the object on which the function has to be invoked:
class auto_switch{
void (led::*action)();
led *ld;
public:
auto_switch(void(led::*a)(), led*l) : action(a), ld(l) {}
void go () { (ld->*action)(); }
};
// usage:
auto_switch s(&led::turn_off, &l1);
s.go();
Online demo
Option 3 : the functional way (may that's what you're looking for ?)
Another variant would be to use the standard functional library to bind a member function and the object on which it shall be executed (as well as any need parameters):
class auto_switch{
std::function<void()> action;
public:
auto_switch(function<void()>a) : action(a) {}
void go () { action(); }
};
Here you can bind anything: any function of any class:
auto_switch s(bind(&led::turn_off, l1));
s.go();
auto_switch s2(bind(&blinking_led::blink, l2));
s2.go();
Online demo
Option 4 : command pattern
Now if you want to perform something on an object when you turn on and off the switch, but you need total flexibility, you can just implement the command pattern : this lets you execute anything on any object. And you don't even need a function pointer.

Use case of dynamic_cast

In many places you can read that dynamic_cast means "bad design". But I cannot find any article with appropriate usage (showing good design, not just "how to use").
I'm writing a board game with a board and many different types of cards described with many attributes (some cards can be put on the board). So I decided to break it down to the following classes/interfaces:
class Card {};
class BoardCard : public Card {};
class ActionCard : public Card {};
// Other types of cards - but two are enough
class Deck {
Card* draw_card();
};
class Player {
void add_card(Card* card);
Card const* get_card();
};
class Board {
void put_card(BoardCard const*);
};
Some guys suggested that I should use only one class describing a card. But I would mean many mutually excluding attributes. And in the case of the Board class' put_card(BoardCard const&) - it is a part of the interface that I cannot put any card on the board. If I had only one type of card I would have to check it inside the method.
I see the flow like the following:
a generic card is in the deck (it's not important what its type is)
a generic card is drawn from the deck and given to a player (the same as above)
if a player chosen a BoardCard then it can be put on the board
So I use dynamic_cast before putting a card on the board. I think that using some virtual method is out of the question in this case (additionally I wouldn't make any sense to add some action about board to every card).
So my question is: What have I designed badly? How could I avoid dynamic_cast? Using some type attribute and ifs would be a better solution...?
P.S.
Any source treating about dynamic_cast usage in the context of design is more than appreciated.
Yes, dynamic_cast is a code smell, but so is adding functions that try to make it look like you have a good polymorphic interface but are actually equal to a dynamic_cast i.e. stuff like can_put_on_board. I'd go as far as to say that can_put_on_board is worse - you're duplicating code otherwise implemented by dynamic_cast and cluttering the interface.
As with all code smells, they should make you wary and they don't necessarily mean that your code is bad. This all depends on what you're trying to achieve.
If you're implementing a board game that will have 5k lines of code, two categories of cards, then anything that works is fine. If you're designing something larger, extensible and possibly allowing for cards being created by non-programmers (whether it's an actual need or you're doing it for research) then this probably won't do.
Assuming the latter, let's look at some alternatives.
You could put the onus of applying the card properly to the card, instead of some external code. E.g. add a play(Context& c) function to the card (the Context being a means to access the board and whatever may be necessary). A board card would know that it may only be applied to a board and a cast would not be necessary.
I would entirely give up using inheritance however. One of its many issues is how it introduces a categorisation of all cards. Let me give you an example:
you introduce BoardCard and ActionCard putting all cards in these two buckets;
you then decide that you want to have a card that can be used in two ways, either as an Action or a Board card;
let's say you solved the issue (through multiple-inheritance, a BoardActionCard type, or any different way);
you then decide you want to have card colours (as in MtG) - how do you do this? Do you create RedBoardCard, BlueBoardCard, RedActionCard etc?
Other examples of why inheritance should be avoided and how to achieve runtime polymorphism otherwise you may want to watch Sean Parent's excellent "Inheritance is the Base Class of Evil" talk. A promising looking library that implements this sort of polymorphism is dyno, I have not tried it out yet though.
A possible solution might be:
class Card final {
public:
template <class T>
Card(T model) :
model_(std::make_shared<Model<T>>(std::move(model)))
{}
void play(Context& c) const {
model_->play(c);
}
// ... any other functions that can be performed on a card
private:
class Context {
public:
virtual ~Context() = default;
virtual void play(Context& c) const = 0;
};
template <class T>
class Model : public Context {
public:
void play(Context& c) const override {
play(model_, c);
// or
model_.play(c);
// depending on what contract you want to have with implementers
}
private:
T model_;
};
std::shared_ptr<const Context> model_;
};
Then you can either create classes per card type:
class Goblin final {
void play(Context& c) const {
// apply effects of card, e.g. take c.board() and put the card there
}
};
Or implement behaviours for different categories, e.g. have a
template <class T>
void play(const T& card, Context& c);
template and then use enable_if to handle it for different categories:
template <class T, class = std::enable_if<IsBoardCard_v<T>>
void play(const T& card, Context& c) {
c.board().add(Card(card));
}
where:
template <class T>
struct IsBoardCard {
static constexpr auto value = T::IS_BOARD_CARD;
};
template <class T>
using IsBoardCard_v = IsBoardCard<T>::value;
then defining your Goblin as:
class Goblin final {
public:
static constexpr auto IS_BOARD_CARD = true;
static constexpr auto COLOR = Color::RED;
static constexpr auto SUPERMAGIC = true;
};
which would allow you to categorise your cards in many dimensions also leaving the possibility to entirely specialise the behaviour by implementing a different play function.
The example code uses std::shared_ptr to store the model, but you can definitely do something smarter here. I like to use a static-sized storage and only allow Ts of a certain maximum size and alignment to be used. Alternatively you could use a std::unique_ptr (which would disable copying though) or a variant leveraging small-size optimisation.
Why not use dynamic_cast
dynamic_cast is generally disliked because it can be easily abused to completely break the abstractions used. And it is not wise to depend on specific implementations. Of course it may needed, but really rarely, so nearly everyone takes a rule of thumb - probably you should not use it. It's a code smell that may imply that you should rethink Your abstractions because they may be not the ones needed in Your domain. Maybe in Your game the Board should not have put_card method - maybe instead card should have method play(const PlaySpace *) where Board implements PlaySpace or something like that. Even CppCoreGuidelines discourage using dynamic_cast in most cases.
When use
Generally few people ever have problems like this but I came across it multiple times already. The problem is called Double (or Multiple) Dispatch. Here is pretty old, but quite relevant article about double dispatch (mind the prehistoric auto_ptr):
http://www.drdobbs.com/double-dispatch-revisited/184405527
Also Scott Meyers in one of his books wrote something about building double dispatch matrix with dynamic_cast. But, all in all, these dynamic_casts are 'hidden` inside this matrix - users don't know what kind of magic happens inside.
Noteworthy - multiple dispatch is also considered code smell :-).
Reasonable alternative
Check out the visitor pattern. It can be used as replace for dynamic_cast but it is also some kind of code smell.
I generally recommend using dynamic_cast and visitor as a last resort tools for design problems as they break abstraction which increases complexity.
You could apply the principles behind Microsoft's COM and provide a series of interfaces, with each interface describing a set of related behaviors. In COM you determine if a specific interface is available by calling QueryInterface, but in modern C++ dynamic_cast works similarly and is more efficient.
class Card {
virtual void ~Card() {} // must have at least one virtual method for dynamic_cast
};
struct IBoardCard {
virtual void put_card(Board* board);
};
class BoardCard : public Card, public IBoardCard {};
class ActionCard : public Card {};
// Other types of cards - but two are enough
class Deck {
Card* draw_card();
};
class Player {
void add_card(Card* card);
Card const* get_card();
};
class Board {
void put_card(Card const* card) {
const IBoardCard *p = dynamic_cast<const IBoardCard*>(card);
if (p != null) p->put_card(this);
};
That may be a bad example, but I hope you get the idea.
It seems to me that the two types of cards are quite different. The things a board card and an action card can do are mutually exclusive, and the common thing is just that they can be drawn from the deck. Moreover, that's not a thing a card does, it's a player / deck action.
If this is true, a question one should ask is whether they should really descend from a common type, Card. An alternative design would be that of a tagged union: let Card instead be a std::variant<BoardCard, ActionCard...>, and contain an instance of the appropriate type. When deciding what to do with the card, you use a switch on the index() and then std::get<> only the appropriate type. This way you don't need any *_cast operator, and get a complete freedom of what methods (neither of which would make sense for the other types) each type of card supports.
If it's only almost true but not for all types, you can variate slightly: only group together those types of cards that can sensibly be superclassed, and put the set of those common types into the variant.
I always found the usage of a cast a code smell, and in my experience, the 90% of the time the cast was due to bad design.
I saw usage of dynamic_cast in some time-critical application where it was providing more performance improvement than inherit from multiple interfaces or retrieving an enumeration of some kind from the object (like a type). So the code smelt, but the usage of the dynamic cast was worth it in that case.
That said, I will avoid dynamic cast in your case as well as multiple inheritances from different interfaces.
Before reaching my solution, your description sounds like there are a lot of details omitted about the behavior of the cards or the consequence they have on the board
and the game itself. I used that as a further constraint, trying to keep thing boxed and maintainable.
I would go for a composition instead of an inheritance. It will provide you evenly the chance of using the card as a 'factory':
it can spawn more game modifiers - something to be applied to the board, and one to a specific enemy
the card can be reused - the card could stays in the hands of the player and the effect on the game is detached from it (there is no 1-1 binding between cards and effects)
the card itself can sit back on the deck, while the effects of what it did are still alive on the board.
a card can have a representation (drawing methods) and react to the touch in a way, where instead the BoardElement can be evenly a 3d miniature with animation
See [https://en.wikipedia.org/wiki/Composition_over_inheritance for further details]. I'd like to quote:
Composition also provides a more stable business domain in the long term as it is less prone to the quirks of the family members.In other words, it is better to compose what an object can do (HAS - A) than extend what it is(IS - A).[1]
A BoardCard/Element can be something like this:
//the card placed on the board.
class BoardElement {
public:
BoardElement() {}
virtual ~BoardElement() {};
//up to you if you want to add a read() methods to read data from the card description (XML / JSON / binary data)
// but that should not be part of the interface. Talking about a potential "Wizard", it's probably more related to the WizardCard - WizardElement relation/implementation
//some helpful methods:
// to be called by the board when placed
virtual void OnBoard() {}
virtual void Frame(const float time) { /*do something time based*/ }
virtual void Draw() {}
// to be called by the board when removed
virtual void RemovedFromBoard() {}
};
the Card could represent something to be used in a deck or in the user's hands, I'll add an interface of that kind
class Card {
public:
Card() {}
virtual ~Card() {}
//that will be invoked by the user in order to provide something to the Board, or NULL if nothing should be added.
virtual std::shared_ptr<BoardElement*> getBoardElement() { return nullptr; }
virtual void Frame(const float time) { /*do something time based*/ }
virtual void Draw() {}
//usefull to handle resources or internal states
virtual void OnUserHands() {}
virtual void Dropped() {}
};
I'd like to add that this pattern allows many tricks inside the getBoardElement() method, from acting as a factory (so something should be spawned with its own lifetime),
returning an Card data member such as a std:shared_ptr<BoardElement> wizard3D; (as example), create a binding between the Card and the BoardElement as for:
class WizardBoardElement : public BoardElement {
public:
WizardBoardElement(const Card* owner);
// other members omitted ...
};
The binding can be useful in order to read some configuration data or whatever...
So inheritance from Card and from BoardElement will be used to implement the features exposed by the base classes and not for providing other methods that can be reached only through a dynamic_cast.
For completeness:
class Player {
void add(Card* card) {
//..
card->OnUserHands();
//..
}
void useCard(Card* card) {
//..
//someway he's got to retrieve the board...
getBoard()->add(card->getBoardElement());
//..
}
Card const* get_card();
};
class Board {
void add(BoardElement* el) {
//..
el->OnBoard();
//..
}
};
In that way, we have no dynamic_cast, Player and board do simple things without knowing about the inner details of the card they are handled, providing good separations between the different objects and increasing maintainability.
Talking about the ActionCard, and about "effects" that may be applied to other players or your avatar, we can think about having a method like:
enum EffectTarget {
MySelf, //a player on itself, an enemy on itself
MainPlayer,
Opponents,
StrongOpponents
//....
};
class Effect {
public:
//...
virtual void Do(Target* target) = 0;
//...
};
class Card {
public:
//...
struct Modifiers {
EffectTarget eTarget;
std::shared_ptr<Effect> effect;
};
virtual std::vector<Modifiers> getModifiers() { /*...*/ }
//...
};
class Player : public Target {
public:
void useCard(Card* card) {
//..
//someway he's got to retrieve the board...
getBoard()->add(card->getBoardElement());
auto modifiers = card->getModifiers();
for each (auto modifier in modifiers)
{
//this method is supposed to look at the board, at the player and retrieve the instance of the target
Target* target = getTarget(modifier.eTarget);
modifier.effect->Do(target);
}
//..
}
};
That's another example of the same pattern to apply the effects from the card, avoiding the cards to know details about the board and it's status, who is playing the card, and keep the code in Player pretty simple.
Hope this may help,
Have a nice day,
Stefano.
What have I designed badly?
The problem is that you always need to extend that code whenever a new type of Card is introduced.
How could I avoid dynamic_cast?
The usual way to avoid that is to use interfaces (i.e. pure abstract classes):
struct ICard {
virtual bool can_put_on_board() = 0;
virtual ~ICard() {}
};
class BoardCard : public ICard {
public:
bool can_put_on_board() { return true; };
};
class ActionCard : public ICard {
public:
bool can_put_on_board() { return false; };
};
This way you can simply use a reference or pointer to ICard and check, if the actual type it holds can be put on the Board.
But I cannot find any article with appropriate usage (showing good design, not just "how to use").
In general I'd say there aren't any good, real life use cases for dynamic cast.
Sometimes I have used it in debug code for CRTP realizations like
template<typename Derived>
class Base {
public:
void foo() {
#ifndef _DEBUG
static_cast<Derived&>(*this).doBar();
#else
// may throw in debug mode if something is wrong with Derived
// not properly implementing the CRTP
dynamic_cast<Derived&>(*this).doBar();
#endif
}
};
I think that I would end up with something like this (compiled with clang 5.0 with -std=c++17). I'm couroius about your comments. So whenever I want to handle different types of Cards I need to instantiate a dispatcher and supply methods with proper signatures.
#include <iostream>
#include <typeinfo>
#include <type_traits>
#include <vector>
template <class T, class... Args>
struct any_abstract {
static bool constexpr value = std::is_abstract<T>::value || any_abstract<Args...>::value;
};
template <class T>
struct any_abstract<T> {
static bool constexpr value = std::is_abstract<T>::value;
};
template <class T, class... Args>
struct StaticDispatcherImpl {
template <class P, class U>
static void dispatch(P* ptr, U* object) {
if (typeid(*object) == typeid(T)) {
ptr->do_dispatch(*static_cast<T*>(object));
return;
}
if constexpr (sizeof...(Args)) {
StaticDispatcherImpl<Args...>::dispatch(ptr, object);
}
}
};
template <class Derived, class... Args>
struct StaticDispatcher {
static_assert(not any_abstract<Args...>::value);
template <class U>
void dispatch(U* object) {
if (object) {
StaticDispatcherImpl<Args...>::dispatch(static_cast<Derived *>(this), object);
}
}
};
struct Card {
virtual ~Card() {}
};
struct BoardCard : Card {};
struct ActionCard : Card {};
struct Board {
void put_card(BoardCard const& card, int const row, int const column) {
std::cout << "Putting card on " << row << " " << column << std::endl;
}
};
struct UI : StaticDispatcher<UI, BoardCard, ActionCard> {
void do_dispatch(BoardCard const& card) {
std::cout << "Get row to put: ";
int row;
std::cin >> row;
std::cout << "Get row to put:";
int column;
std::cin >> column;
board.put_card(card, row, column);
}
void do_dispatch(ActionCard& card) {
std::cout << "Handling action card" << std::endl;
}
private:
Board board;
};
struct Game {};
int main(int, char**) {
Card* card;
ActionCard ac;
BoardCard bc;
UI ui;
card = &ac;
ui.dispatch(card);
card = &bc;
ui.dispatch(card);
return 0;
}
As I can't see why you wouldn't use virtual methods, I'm just gonna present, how I would do it. First I have the ICard interface for all cards. Then I would distinguish, between the card types (i.e. BoardCard and ActionCard and whatever cards you have). And All the cards inherit from either one of the card types.
class ICard {
virtual void put_card(Board* board) = 0;
virtual void accept(CardVisitor& visitor) = 0; // See later, visitor pattern
}
class ActionCard : public ICard {
void put_card(Board* board) final {
// std::cout << "You can't put Action Cards on the board << std::endl;
// Or just do nothing, if the decision of putting the card on the board
// is not up to the user
}
}
class BoardCard : public ICard {
void put_card(Board* board) final {
// Whatever implementation puts the card on the board, mb something like:
board->place_card_on_board(this);
}
}
class SomeBoardCard : public BoardCard {
void accept(CardVisitor& visitor) final { // visitor pattern
visitor.visit(this);
}
void print_information(); // see BaseCardVisitor in the next code section
}
class SomeActionCard : public ActionCard {
void accept(CardVisitor& visitor) final { // visitor pattern
visitor.visit(this);
}
void print_information(); // see BaseCardVisitor
}
class Board {
void put_card(ICard* const card) {
card->put_card(this);
}
void place_card_on_board(BoardCard* card) {
// place it on the board
}
}
I guess the user has to know somehow what card he has drawn, so for that I would implement the visitor pattern. You could also place the accept-method, which I placed in the most derived classes/cards, in the card types (BoardCard, ActionCard), depeneding on where you want to draw the line on what information shall be given to the user.
template <class T>
class BaseCardVisitor {
void visit(T* card) {
card->print_information();
}
}
class CardVisitor : public BaseCardVisitor<SomeBoardCard>,
public BaseCardVisitor<SomeActionCard> {
}
class Player {
void add_card(ICard* card);
ICard const* get_card();
void what_is_this_card(ICard* card) {
card->accept(visitor);
}
private:
CardVisitor visitor;
};
Hardly a complete answer but just wanted to pitch in with an answer similar to Mark Ransom's but just very generally speaking, I've found downcasting to be useful in cases where duck typing is really useful. There can be certain architectures where it is very useful to do things like this:
for each object in scene:
{
if object can fly:
make object fly
}
Or:
for each object in scene that can fly:
make object fly
COM allows this type of thing somewhat like so:
for each object in scene:
{
// Request to retrieve a flyable interface from
// the object.
IFlyable* flyable = object.query_interface<IFlyable>();
// If the object provides such an interface, make
// it fly.
if (flyable)
flyable->fly();
}
Or:
for each flyable in scene.query<IFlyable>:
flyable->fly();
This implies a cast of some form somewhere in the centralized code to query and obtain interfaces (ex: from IUnknown to IFlyable). In such cases, a dynamic cast checking run-time type information is the safest type of cast available. First there might be a general check to see if an object provides the interface that doesn't involve casting. If it doesn't, this query_interface function might return a null pointer or some type of null handle/reference. If it does, then using a dynamic_cast against RTTI is the safest thing to do to fetch the actual pointer to the generic interface (ex: IInterface*) and return IFlyable* to the client.
Another example is entity-component systems. In that case instead of querying abstract interfaces, we retrieve concrete components (data):
Flight System:
for each object in scene:
{
if object.has<Wings>():
make object fly using object.get<Wings>()
}
Or:
for each wings in scene.query<Wings>()
make wings fly
... something to this effect, and that also implies casting somewhere.
For my domain (VFX, which is somewhat similar to gaming in terms of application and scene state), I've found this type of ECS architecture to be the easiest to maintain. I can only speak from personal experience, but I've been around for a long time and have faced many different architectures. COM is now the most popular style of architecture in VFX and I used to work on a commercial VFX application used widely in films and games and archviz and so forth which used a COM architecture, but I've found ECS as popular in game engines even easier to maintain than COM for my particular case*.
One of the reasons I find ECS so much easier is because the bulk of the systems in this domain like PhysicsSystem, RenderingSystem, AnimationSystem, etc. boil down to just data transformers and the ECS model just fits beautifully for that purpose without abstractions getting in the way. With COM in this domain, the number of subtypes implementing an interface like a motion interface like IMotion might be in the hundreds (ex: a PointLight which implements IMotion along with 5 other interfaces), requiring hundreds of classes implementing different combinations of COM interfaces to maintain individually. With the ECS, it uses a composition model over inheritance, and reduces those hundreds of classes down to just a couple dozen simple component structs which can be combined in endless ways by the entities that compose them, and only a handful of systems have to provide behavior: everything else is just data which the systems loop through as input to then provide some output.
Between legacy codebases that used a bunch of global variables and brute force coding (ex: sprinkling conditionals all over the place instead of using polymorphism), deep inheritance hierarchies, COM, and ECS, in terms of maintainability for my particular domain, I'd say ECS > COM, while deep inheritance hierarchies and brute force coding with global variables all over the place were both incredibly hard to maintain (OOP using deep inheritance with protected data fields is almost as hard to reason about in terms of maintaining invariants as a boatload of global variables IMO, but further can invite the most nightmarish cascading changes spilling across entire hierarchies if designs need to change -- at least the brute force legacy codebase didn't have the cascading problem since it was barely reusing any code to begin with).
COM and ECS are somewhat similar except with COM, the dependencies flow towards central abstractions (COM interfaces provided by COM objects, like IFlyable). With an ECS, the dependencies flow towards central data (components provided by ECS entities, like Wings). At the heart of both is often the idea that we have a bunch of non-homogeneous objects (or "entities") of interest whose provided interfaces or components are not known in advance, since we're accessing them through a non-homogeneous collection (ex: a "Scene"). As a result we need to discover their capabilities at runtime when iterating through this non-homogeneous collection by either querying the collection or the objects individually to see what they provide.
Either way, both involve some type of centralized casting to retrieve either an interface or a component from an entity, and if we have to downcast, then a dynamic_cast is at least the safest way to do that which involves runtime type checking to make sure the cast is valid. And with both ECS and COM, you generally only need one line of code in the entire system which performs this cast.
That said, the runtime checking does have a small cost. Typically if dynamic_cast is used in COM and ECS architectures, it's done in a way so that a std::bad_cast should never be thrown and/or that dynamic_cast itself never returns nullptr (the dynamic_cast is just a sanity check to make sure there are no internal programmer errors, not as a way to determine if an object inherits a type). Another type of runtime check is made to avoid that (ex: just once for an entire query in an ECS when fetching all PosAndVelocity components to determine which component list to use which is actually homogeneous and only stores PosAndVelocity components). If that small runtime cost is non-negligible because you're looping over a boatload of components every frame and doing trivial work to each, then I found this snippet useful from Herb Sutter in C++ Coding Standards:
template<class To, class From> To checked_cast(From* from) {
assert( dynamic_cast<To>(from) == static_cast<To>(from) && "checked_cast failed" );
return static_cast<To>(from);
}
template<class To, class From> To checked_cast(From& from) {
assert( dynamic_cast<To>(from) == static_cast<To>(from) && "checked_cast failed" );
return static_cast<To>(from);
}
It basically uses dynamic_cast as a sanity check for debug builds with an assert, and static_cast for release builds.

SystemC/TLM (C++) sharing memory pool; static members, static methods, Singleton or?

Context:
I am writing a specific communication protocol to be used between TLM models (HW blocks described with SystemC and thus C++).
TLM notion is not important, just note that this communication is mimicked by allocating objects, the generic payloads (gps), that are passed between these C++ models of HW blocks.
Aim:
Together with the protocol, I want to provide a memory manager that should be able to efficiently handle the gps; this is quite important since in one simulation lots of gps are constructed, used and destroyed and this can slow down things a lot.
My goal is also to create something simple that could be used by others without efforts.
Issues:
The first issue I had was in creating a single shared pool for all the blocks communicating with that protocol. I thought about creating a static member in the mm class, but then I realized that:
Static members require a definition in the cpp. This makes the mm class less intuitive to use (with different people using this, some will forget to do so) and I would prefer to avoid that.
Depending on where (and in which?) in the cpp file the static variable definition is done, the pool might not have wet the parameters needed to be initialized (i.e., the number of mm instances created).
The second issue is similar to the first one. I want to count the number of instances and thus instead of a pool I need to create a shared counter to be used then by the pool to initialize itself. Again, I wanted to avoid static variable definitions in a cpp file and to guarantee the order of initialization.
I have considered mainly:
static members (discarded for the reasons above)
Singletons (discarded because I don't need to create a whole class for the pool to make it visible by others and single-instanced)
static methods (the approaches I finally picked and that is not far from a complete Singleton)
This is the code I produced (only relevant part included):
/**
* Helper class to count another class' number of instances.
*/
class counter {
public:
// Constructor
counter() : count(0) {}
//Destructor
virtual ~counter() {}
private:
unsigned int count;
public:
unsigned int get_count() {return count;}
void incr_count() {count++;}
void decr_count() {count--;}
};
template <unsigned int MAX = 1>
class mm: public tlm::tlm_mm_interface {
//////////////////////////////TYPEDEFS AND ENUMS/////////////////////////////
public:
typedef tlm::tlm_generic_payload gp_t;
///////////////////////////CLASS (CON/DE)STRUCTOR////////////////////////////
public:
// Constructor
mm() {inst_count().incr_count();}
// Copy constructor
mm(const mm&) {inst_count().incr_count();}
// Destructor
virtual ~mm() {} // no need to decrease instance count in our case
////////////////////////////////CLASS METHODS////////////////////////////////
public:
// Counter for number of isntances.
static counter& inst_count() {
static counter cnt;
return cnt;
}
/* This pattern makes sure that:
-- 1. The pool is created only when the first alloc appears
-- 2. All instances of mm have been already created (known instance sequence)
-- 3. Only one pool exists */
static boost::object_pool<gp_t>& get_pool() {
static boost::object_pool<gp_t> p(
mm<MAX>::inst_count().get_count() * MAX / 2, // creation size
mm<MAX>::inst_count().get_count() * MAX // max size used
);
return p;
}
// Allocate
virtual gp_t* allocate() {
//...
return gp;
}
// Free the generic payload and data_ptr
virtual void free(gp_t* gp) {
//...
get_pool().destroy(gp);
}
}
Now, the initiator block class header should have a member:
mm m_mm;
And the initiator block class cpp should use this like:
tlm_generic_payload* gp;
gp = m_mm.allocate();
//...
m_mm.free(gp); // In truth this is called by gp->release()...
// ...not important here
Having an electronic HW background, I am mainly trying to improve coding style, learn new approaches and optimize speed/memory allocation.
Is there a better way to achieve this? In particular considering my doubts:
It seems to me a not optimal workaround to encapsulate the counter in a class, put it locally (but static) in a static method and then do the same for the pool.
even though SystemC "simulation kernel" is single-threaded, I need to consider a multithread case...I am not sure that the relationship between those two static methods is safe even thou independently they should be safe...with C++03 g++ adds code to guarantee it and with C++11:
ยง6.7 [stmt.dcl] p4 If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
Thanks in advance.