I've been working on this issue since the last 2 days and i've no clue of what's going on
I also searched on stackoverflow but i couldn't find an answer
This is an Arduino project and i'm trying to use c and c++ to write the most reusable and clean code possible
I've got these classes:
Enum.h
#pragma once
#include <Arduino.h>
class Enum {
public:
const char *name;
uint8_t id;
static const Enum* getValues();
static uint8_t getSize();
static const Enum** getValueById(uint8_t id);
Enum();
Enum(uint8_t id, const char *name);
bool operator== (const Enum &e);
};
Enum.cpp
#include "Enum.h"
Enum::Enum() {}
Enum::Enum(uint8_t id, const char *name) {
this->name = name;
this->id = id;
};
bool Enum::operator== (const Enum &e)
{
return id == e.id;
}
Carstatus.h
#pragma once
#include "Enum.h"
#include "CanbusMessageType.h"
class Carstatus : public Enum {
public:
static const Carstatus *EXTERNAL_TEMPERATURE;
static const Carstatus *INTERNAL_TEMPERATURE;
static const Carstatus *SPEED;
static const Carstatus *INTERNAL_LUMINANCE;
static const Carstatus *FRONT_DISTANCE;
static const Carstatus *ENGINE_WATER_COOLING_TEMPERATURE;
static const Carstatus *ENGINE_OIL_TEMPERATURE;
static const Carstatus *ENGINE_INTAKE_MANIFOLD_PRESSURE;
static const Carstatus *ENGINE_RPM;
static const Carstatus *TRIP_DURATION;
static const Carstatus *TRIP_AVERAGE_SPEED;
static const Carstatus *TRIP_MAX_SPEED;
static const Enum* getValueById(uint8_t id);
static const Enum** getValues();
static uint8_t getSize();
const CanbusMessageType *type;
Carstatus(uint8_t id, const char *name, const CanbusMessageType *type);
private:
static const Enum* values[];
static uint8_t index;
};
Carstatus.cpp
#include "Carstatus.h"
Carstatus::Carstatus(uint8_t id, const char *name, const CanbusMessageType *type) : Enum(id, name) {
this->type = type;
values[index] = this;
index++;
};
const Enum* Carstatus::getValueById(uint8_t id) {
for(uint8_t i = 0; i < getSize(); i++) {
if(values[i]->id == id) {
return values[i];
}
}
return nullptr;
}
uint8_t Carstatus::getSize() {
return Carstatus::index;
}
const Enum** Carstatus::getValues() {
return Carstatus::values;
}
const Enum* Carstatus::values [12] = { 0 };
uint8_t Carstatus::index = 0;
const Carstatus* Carstatus::EXTERNAL_TEMPERATURE = new Carstatus(0x00, "EXTERNAL_TEMPERATURE", CanbusMessageType::FLOAT);
const Carstatus* Carstatus::INTERNAL_TEMPERATURE = new Carstatus(0x01, "INTERNAL_TEMPERATURE", CanbusMessageType::FLOAT);
const Carstatus* Carstatus::SPEED = new Carstatus(0x02, "SPEED", CanbusMessageType::INT);
const Carstatus* Carstatus::INTERNAL_LUMINANCE = new Carstatus(0x03, "INTERNAL_LUMINANCE", CanbusMessageType::INT);
const Carstatus* Carstatus::FRONT_DISTANCE = new Carstatus(0x04, "FRONT_DISTANCE", CanbusMessageType::FLOAT);
const Carstatus* Carstatus::ENGINE_WATER_COOLING_TEMPERATURE = new Carstatus(0x05, "ENGINE_WATER_COOLING_TEMPERATURE", CanbusMessageType::FLOAT);
const Carstatus* Carstatus::ENGINE_OIL_TEMPERATURE = new Carstatus(0x06, "ENGINE_OIL_TEMPERATURE", CanbusMessageType::FLOAT);
const Carstatus* Carstatus::ENGINE_INTAKE_MANIFOLD_PRESSURE = new Carstatus(0x07, "ENGINE_INTAKE_MANIFOLD_PRESSURE", CanbusMessageType::FLOAT);
const Carstatus* Carstatus::ENGINE_RPM = new Carstatus(0x08, "ENGINE_RPM", CanbusMessageType::INT);
const Carstatus* Carstatus::TRIP_DURATION = new Carstatus(0x09, "TRIP_DURATION", CanbusMessageType::STRING);
const Carstatus* Carstatus::TRIP_AVERAGE_SPEED = new Carstatus(0x0A, "TRIP_AVERAGE_SPEED", CanbusMessageType::INT);
const Carstatus* Carstatus::TRIP_MAX_SPEED = new Carstatus(0x0B, "TRIP_MAX_SPEED", CanbusMessageType::INT);
CanbusMessageType.h
#pragma once
#include "Enum.h"
class CanbusMessageType : public Enum {
public:
static const CanbusMessageType* INT;
static const CanbusMessageType* FLOAT;
static const CanbusMessageType* STRING;
static const CanbusMessageType* BOOL;
static const Enum* getValueById(uint8_t id);
static const Enum** getValues();
static uint8_t getSize();
CanbusMessageType(uint8_t id, const char *name);
private:
static const Enum* values[];
static uint8_t index;
};
CanbusMessageType.cpp
#include "CanbusMessageType.h"
CanbusMessageType::CanbusMessageType(uint8_t id, const char *name) : Enum(id, name) {
values[index] = this;
index++;
};
const Enum* CanbusMessageType::getValueById(uint8_t id) {
for(uint8_t i = 0; i < getSize(); i++) {
if(values[i]->id == id) {
return values[i];
}
}
return nullptr;
}
uint8_t CanbusMessageType::getSize() {
return index;
}
const Enum** CanbusMessageType::getValues() {
return values;
}
const Enum* CanbusMessageType::values [4] = { 0 };
uint8_t CanbusMessageType::index = 0;
const CanbusMessageType* CanbusMessageType::INT = new CanbusMessageType(0x00, "INT");
const CanbusMessageType* CanbusMessageType::FLOAT = new CanbusMessageType(0x01, "FLOAT");
const CanbusMessageType* CanbusMessageType::STRING = new CanbusMessageType(0x02, "STRING");
const CanbusMessageType* CanbusMessageType::BOOL = new CanbusMessageType(0x03, "BOOL");
What i'm trying to achieve is a class that is emulating (somehow) java enums but I cannot understand why instantiated Carstatus objects (EXTERNAL_TEMPERATURE, INTERNAL_TEMPERATURE, ecc...) have type member equals to nullptr
I attach an online example: text You can found here full code: text
Someone have got some hints? Thank you
I also tried to replace CanbusMessageType with uint8_t to store CanbusMessageType::id but it wont work
what's happening is called Static Initialization Order Fiasco which means any object that requires heap allocation to be initialized (and therefore non-trivial) will be initialized in any order at runtime.
the solution here is to simply avoid java's new everything
and allocate those CanbusMessageType
objects inside your binary, and avoid heap allocations whenever possible.
class CanbusMessageType : public Enum {
public:
static const CanbusMessageType INT;
static const CanbusMessageType FLOAT;
static const CanbusMessageType STRING;
static const CanbusMessageType BOOL;
static const Enum* getValueById(uint8_t id);
static const Enum** getValues();
static uint8_t getSize();
CanbusMessageType(uint8_t id, const char *name);
private:
static const Enum* values[];
static uint8_t index;
};
const CanbusMessageType CanbusMessageType::INT = CanbusMessageType(0x00, "INT");
...
another way to guarantee the order of initialization of objects is to initialize them yourself at runtime, by creating any "initialization function" and have it create the objects at runtime.