my problem is the following: I have 2 classes which both contain vector of data, the vector length and the data struct is very big and almost 90% of the data is sam between the 2 classes. Current implementation is that each class holds its own vector of data thus there is big memory consumption.
My goal is to optimize the memory and create some kind of DB where it will hold the data, and the classes will hold some kind of reference to the DB.
Guidelines:
Each class can manipulate its vector of data and it needs to reflect on the DB, means that for example both classes hold a ref to the same data struct and one of the classes removes it from its vector, the DB still need to hold the data for the second class.
if no class hold ref to data, the data needs to be deleted from DB.
if both classes hold the same data, I don't want replication.
My design was to use some kind of a hash map where the classes will hold key to the map, and the hash map itself will hold a reference count, but than I thought about smart pointers in C++.
This is the code for my design but I am not sure regarding my implementation:
class Data {
public:
Data(const int xTemp, const int yTemp, const int idTemp) {
x = xTemp;
y = yTemp;
id = idTemp;
}
int getX() { return x; }
int getY() { return y; }
int getId() { return id; }
private:
int x;
int y;
int id;
};
class ModelA {
public:
ModelA() {
vector.clear();
}
private:
std::vector<std::tuple<int /*key to DB */, std::shared_ptr<Data> /* ptr to data */, std::string /* id Type per Model */> > vector;
};
class ModelB {
ModelB() {
vector.clear();
}
private:
std::vector<std::tuple<int /*key to DB */, std::shared_ptr<Data> /* ptr to data */, std::string /* id Type per Model */> > vector;
};
std::unordered_map<int, std::shared_ptr<Data> > db;
Basically we can insert elements to modelA and modelB and we don't want to have same memory if the data is the same(based on id).
Thanks.
You could make your scheme work along these lines:
class Database {
std::unordered_map<int, std::weak_ptr<Data> > db;
public:
std::shared_ptr<Data> add(int key, const Data& val) {
std::weak_ptr<Data>& wp = db[key];
std::shared_ptr<Data> ret = wp.lock();
if (!ret) {
ret = std::make_shared<Data>(val);
wp = ret;
}
return ret;
}
// Must be called **after** disposing of your copy of
// the `shared_ptr<Data>`
void remove(int key) {
if (db[key].expired()) {
// No more references.
db.erase(key);
}
}
};
Upon further thought, remove could be called automatically by a deleter. Something like this (not tested):
class Database {
std::unordered_map<int, std::weak_ptr<Data> > db;
struct Deleter {
Database* db;
int key;
void operator()(const Data* ptr) {
db->remove(key);
delete ptr;
}
};
public:
std::shared_ptr<Data> add(int key, const Data& val) {
std::weak_ptr<Data>& wp = db[key];
std::shared_ptr<Data> ret = wp.lock();
if (!ret) {
ret = std::shared_ptr<Data>(
new Data(val), Deleter{this, key});
wp = ret;
}
return ret;
}
private:
void remove(int key) {
assert(db[key].expired());
db.erase(key);
}
};
You lose the optimization of make_shared that uses a single allocation for the object and the control block. Now two heap allocations per Data instance are performed.
Related
I want to design a data dashboard framework with c++ with the following requirements:
clients can register data type to the dashboard using a key (string or integer are both acceptable)
clients can store/access the object with the known data type and key
The following example code demonstrates how I want to use it
// data.hpp
struct DataA
{
DataA();
int a;
};
struct DataF
{
DataF();
float f;
};
// data.cpp
static DataA s_da;
static DataF s_df;
DataA::DataA()
{
if(!Dashboard::Register("A", s_da)) {
cerr << "unable to register DataA, key is used";
}
}
DataF::DataF()
{
if(!Dashboard::Register("F", s_df)) {
cerr << "unable to register DataF, key is used";
}
}
// main.cpp
int main ()
{
DataA da;
da.a = 123;
Dashboard::Set("A", da);
DataF df;
df.f = 3.14;
Dashboard::Set("F", df);
cout << ((DataA)Dashboard::Get("A")).a << endl; // 123
cout << ((DataF)Dashboard::Get("F")).f << endl; // 3.14
return 0;
}
However, I can't come up with any idea to implement the Dashboard class to provide the interface.
How could I dynamically register an object with a given datatype and key? Is there any design pattern that addresses this requirement?
I built something like you are describing on my team as an internal for a library that was used for routing messages across the application.
If you are stuck on C++11 (such that std::any or std::variant is unavailable), you could have an empty virtual base class type as follows:
class BaseValue
{
public:
BaseValue() {};
virtual ~BaseValue() {}; // need one virtual method for dynamic_cast
};
And a derived template class such as the following:
template <typename T>
class Value : public BaseValue
{
public:
Value(const T& t) : _t(t)
{}
T _t;
};
Then your data structure is this. It's a map between string to BaseValue pointers
unordered_map<string, BaseValue*> dashboard;
We'll smuggle data into the map above by using the template class Value that derives from BaseValue.
Inserting into the the dashboard is like this:
template <typename T>
void insert(const string& name, const T& t)
{
Value<T>* pT = new Value<T>(t);
dashboard.insert(name, pT);
}
Fetching is something like this. There's different ways to structure a "get" call with respect to "not found" scenarios.
template<typename T>
T& get(const string& name, const T& default = {})
{
auto itor = dashboard.find(name);
if (itor != dashboard.end())
{
BaseValue* pBaseValue = itor->second;
T* pValue = dynamic_cast<T*>(pBaseValue);
if (pValue)
{
return pValue->_t;
}
}
return default; // you could also throw an exception
}
Example insert:
DataA da;
da.a = 123;
insert("a", da);
Example fetch:
DataA& da = get<A>("a");
There's a lot of improvements you can make to the above. For starters, you can convert all of helper functions into a class. Use shared_ptr instead of raw pointers internally. etc...
I made a bidirectional and 2-dimensional linked list. My nodes are called chunks, and they contain a pointer to the chunks on their left, right, bottom and top.
class chunk;
typedef std::shared_ptr<chunk> chunk_ptr;
typedef std::weak_ptr<chunk> chunk_wptr;
class chunk
{
public:
chunk(wanted_id) : id(wanted_id) {}
chunk_ptr left() const { return _left.lock(); }
chunk_ptr right() const { return _right.lock(); }
chunk_ptr top() const { return _top.lock(); }
chunk_ptr bottom() const { return _bottom.lock(); }
void left(const chunk_ptr set) { _left = set; }
void right(const chunk_ptr set) { _right = set; }
void top(const chunk_ptr set) { _top = set; }
void bottom(const chunk_ptr set) { _bottom = set; }
int id() const { return _id; }
private:
chunk_wptr _left, _right, _top, _bottom;
int _id;
void id(const int id) { _id = id; }
};
Now, let's imagine that I have built the following structure:
If I want to navigate from 1 to 4, I could use the following line of code:
id4 = id1->right()->right()->bottom();
Now let's imagine that chunk 3 has been removed, e.g. id2->right == id4->top == nullptr:
If I want to access id4 then to perform some operation on it, there will be a runtime error. To avoid to perform a check at each step, I would like to introduce a neutral chunk element:
auto null_chunk = std::make_shared<chunk>(-1); // Let's define its id as -1
null_chunk->left(null_chunk);
null_chunk->right(null_chunk);
null_chunk->top(null_chunk);
null_chunk->bottom(null_chunk);
Thus, the following statement would run succesfully:
id4 = id1->right()->right()->bottom();
And then id4 == null_chunk.
However, I'm not quite sure about how to integrate such an element in my code.
I could use a static variable:
// This is a public static method
chunk_ptr chunk::null_chunk()
{
static auto ptr = instanciate_null_chunk();
return ptr;
}
// This is a private static method
chunk_ptr chunk::instanciate_null_chunk()
{
auto ptr = std::make_shared<chunk>(-1);
ptr->left(ptr);
ptr->right(ptr);
ptr->top(ptr);
ptr->bottom(ptr);
return ptr;
}
Now, I would like to initialize left, right, top and bottom by null_chunk in my constructor:
chunk(wanted_id) : id(wanted_id)
{
this->left(null_chunk());
this->right(null_chunk());
this->top(null_chunk());
this->bottom(null_chunk());
}
This leads to a a recursion stack overflow (null_chunk calling the constructor calling null_chunk etc...).
This forces me to define a specific private constructor for null_chunk(), but because I'm using shared pointers, my constructor must be public to use make_shared...
Thus, there is a design flow. What would be the best way to implement such a feature?
One possible to solution to implement the null node is to use a static member. This member is initialized once using another static function, that creates a shared pointer with the null chunk and redirects all outgoing connections to the chunk itself.
On construction of any other chunk all outgoing connections point to the null chunk as well.
As mentioned in the comments above, make sure not to leak any memory due to circular references.
You have to create a second constructor as you mentioned. However using a private struct as argument prevents any calls to this constructor from outside the class.
class chunk {
public:
using chunk_ptr = std::shared_ptr<chunk>;
using chunk_wptr = std::weak_ptr<chunk>;
private:
int _id;
chunk_wptr _left, _right, _top, _bottom;
static chunk_ptr nullchunk;
struct pctor {};
static chunk_ptr gennull() {
chunk_ptr pnullchunk {std::make_shared<chunk>(pctor{})};
pnullchunk->_left = pnullchunk;
pnullchunk->_right = pnullchunk;
pnullchunk->_top = pnullchunk;
pnullchunk->_bottom = pnullchunk;
return pnullchunk;
}
public:
chunk(pctor) : _id(-1) {}
chunk(int id) : _id(id),
_left(chunk::nullchunk),
_right(chunk::nullchunk),
_top(chunk::nullchunk),
_bottom(chunk::nullchunk) {}
bool isNullNode() const
{ return this == chunk::nullchunk.get(); }
//
// Further functions omitted
//
};
chunk::chunk_ptr chunk::nullchunk {chunk::gennull()};
I have a class idx_aware that goes into a container container, which wraps around a std::vector. When the class is added to container, container sets a pointer to itself in idx_aware, as well as the index of idx_aware in its internal memory storage.
The index is not going to change until the container is destroyed or idx_aware is removed; idx_aware needs to know about its container and its index, because it has some methods that require both to work.
Now this introduces the following problem: when I get a non-const reference to an idx_aware class contained in container, I could assign to it another idx_aware class, which could have a different index. The intention would be assigning all the fields and keeping the index as it is.
#include <vector>
#include <limits>
#include <iostream>
class container;
// Stores a std::size_t field, which can be set only by subclasses.
class with_idx {
std::size_t _i;
public:
with_idx() : _i(std::numeric_limits<std::size_t>::max()) {}
operator std::size_t() const { return _i; }
protected:
void set_idx(std::size_t i) { _i = i; }
};
// Knows its index and its container
class idx_aware : public with_idx {
container const *_container;
int _some_field1;
float _some_field2;
public:
void foo() {
// Do stuff using _container and _i
}
private:
friend class container;
};
// Wraps around a std::vector
class container {
std::vector<idx_aware> _data;
public:
idx_aware &operator[](std::size_t idx) {
// Need non-const access to call foo
return _data[idx];
}
idx_aware const &operator[](std::size_t idx) const {
return _data[idx];
}
std::size_t add(idx_aware const &item) {
// Here it could potentially reuse a freed position
std::size_t free_slot = _data.size();
// Ensure _data is big enough to contain free_slot
if (_data.size() <= free_slot) {
_data.resize(free_slot + 1);
}
// Assign
_data[free_slot] = item;
_data[free_slot].set_idx(free_slot);
_data[free_slot]._container = this;
return free_slot;
}
};
int main() {
container c;
idx_aware an_item;
std::size_t i = c.add(an_item);
std::cout << c[i] << std::endl; // Prints 0
idx_aware another_item; // Created from somewhere else
// I want to set all the data in idx_aware, but the
// index should stay the same!
c[i] = another_item;
std::cout << c[i] << std::endl; // Prints numeric_limits<size_t>::max()
// Now container[i] is broken because it doesn't know anymore its index.
return 0;
}
One possible workaround would be to change with_idx in such a way that when set_idx is called, a flag is set that prevents assignment and copy operator to overwrite the _i property, like this:
class with_idx {
std::size_t _i;
bool _readonly;
public:
with_idx() : _i(std::numeric_limits<std::size_t>::max()), _readonly(false) {}
with_idx(with_idx const &other) : _i(other._i), _readonly(false) {}
with_idx &operator=(with_idx const &other) {
if (!_readonly) {
_i = other._i;
}
return *this;
}
operator std::size_t() const { return _i; }
protected:
void set_idx(std::size_t i) {
_i = i;
if (i != std::numeric_limits<std::size_t>::max()) {
// This has been set by someone with the right to do so,
// prevent overwriting
_readonly = true;
} else {
// Removed from the container, allow overwriting
_readonly = false;
}
}
};
This would have the consequence of returning, after assignment, a reference to an idx_aware class with unchanged index.
idx_aware ¬_in_container1 = /* ... */;
idx_aware ¬_in_container2 = /* ... */;
idx_aware &in_container = /* ... */;
not_in_container1 = in_container = not_in_container2;
// std::size_t(not_in_container_1) != std::size_t(not_in_container_2)
Is there a design pattern that can model this situation in a better way? My searches were not successful.
Are there other unwanted consequences of overriding the assignment operator in this way? The limitation I pointed out in the previous example does not look too "bad".
Is there an easier solution? I thought about writing some proxy object to replace the idx_aware & return type of operator[].
Experience tells that when C++ does not do what you intend, you are likely to be misusing OOP...
Robert's comment suggested me this solution.
Why would the contained object know about its container? To be able to perform actions such as foo and provide shorthand methods that otherwise would require to have access to the container.
Let's take this functionality away from the contained object; the contained object is just data payload. Instead, let's make operator[] return not the contained object, but some sort of iterator, a wrapper around the contained object, which knows the container and the index, and once dereferenced returns the actual contained object.
class was_idx_aware {
int _some_field1;
float _some_field2;
};
class container {
std::vector<idx_aware> _data;
public:
class idx_aware_wrapper {
container const *_container;
std::size_t _idx;
public:
idx_aware_wrapper(container const &c, std::size_t i)
: _container(&c)
, _idx(i)
{}
was_idx_aware const &operator*() const {
return _container->_data[_idx];
}
was_idx_aware &operator*() {
return _container->_data[_idx];
}
void foo() {
// Do stuff using _container and _idx.
}
};
idx_aware_wrapper operator[](std::size_t i) {
return idx_aware_wrapper(*this, i);
}
/* .... */
};
This allows quick access to any data in was_idx_aware, and the wrapper class can be augmented with all the methods that require interaction with the container. No need to store and keep indices up to date or override assignment operators.
Say I have a class with a couple of data members, and I want a class method that returns one, and the next time it is called returns the value of the other. Something like:
class MyClass
{
public:
MyClass():switch(0){};
int get();
private:
int intA, intB;
int sw;
};
int MyClass::get()
{
if ( (++sw)%2 )
return intA;
else
return intB;
}
What would a more elegant way of doing it be? I don't like the if...else statement very much. It's fine for something like return, but if I'm actually using more complex operations, I end up duplicating a ton of code. Or having to create a second method within each method that is called after I resolve what element I'm pointing to.
What I'd prefer to do, ideally, is to use some form of pointer, so I can do
class MyClass
{
public:
MyClass():switch(&intA){};
int get();
void toggleSwitch();
private:
int intA, intB;
int * sw;
};
int MyClass::get()
{
return *sw;
}
void MyClass::toggleSwitch()
{
if ( sw == &intA )
sw = &intB;
else
sw = &intA;
}
Or something to that effect. I could call toggleSwitch(), and have my class operate on either one or the other value easily.
I still don't like it though. I prefer to avoid if's when possible, and I shouldn't need one in this case. This use of a naked pointer should be pretty safe, but I was thinking I could have something like std::unique_ptr holding each element and then std::swap them. But then the pointers would own the elements, and they'd be dynamic memory instead.
So is there a better way to do it?
Well, switch is a keyword, but I'll roll with it. How about an array of pointers?
int *fields[] = {&intA, &intB};
int MyClass::get()
{
return *fields[++switch % 2];
}
This would expand nicely if you could have additional variables later.
Or maybe:
int MyClass::get()
{
return *fields[switch = 1 - switch];
}
If you return a reference then you could use get() internally.
int &MyClass::get()
{
return *fields[switch = 1 - switch];
}
I would encapsulate the concept of a toggling value:
template<typename T>
class Toggleable {
T first;
T second;
T* current;
T* other;
public:
Toggleable(const T& first, const T& second)
: first(first),
second(second),
current(&first),
other(&second) {
}
bool toggle() {
std::swap(current, other);
}
const T& get() const {
return *current;
}
}
Then use as:
class MyClass
{
Toggleable<int> value;
public:
MyClass()
: value(42, 1729)
{
}
const int& get() {
value.toggle();
return value.get();
}
};
I'm trying to map some structs to some other instances, like this:
template <typename T>
class Component {
public:
typedef std::map<EntityID, T> instances_map;
instances_map instances;
Component() {};
T add(EntityID id) {
T* t = new T();
instances[id] = *t;
return *t;
};
};
Then I use it like this:
struct UnitInfos {
int owner_id;
int health;
float x, y;
};
class LogicComponent : public Component<UnitInfos> {};
The problem is that when it later retrieve data later on, like this:
comp.instance[id];
I get a breand new object with properties initialized at default values.
Is there something inherently wrong with this piece of code, or am I leaving out information about the problem?
As per #aaa suggestion, i change the code to
typedef std::map<EntityID, T> instances_map;
instances_map instances;
T& add(EntityID id) {
instances[id] = T();
return instances[id];
};
but when I access it
UnitInfos &info = logic_c.instances[id];
the value of info.x is still 0. Any pointers?
The problem was how I stored the reference to LogicComponent in another class. using LogicComponent logic_c; instead of LogicComponent& logic_c;. It now works, but I'm storing pointers in the map (instead of #aaa's suggestion). Is this a bad idea?
Clarify the operations you want to perform on LogicComponent. Assuming you are trying to achieve something like this:
Step 1: Add a new entry to the map:
LogicComponent comp;
EntityID id = 99;
UnitInfos info = comp.add(id);
Step 2: Initialize the info:
info.x = 10.0;
info.y = 11.0
// etc
Step 3: Get the info object again:
UnitInfos info2 = comp.instances[id]; // this is uninitialized.
Then, a few code comments are in order:
The info object returned by comp.add is a COPY of the object you added to the map. By modifying it, you are not modifying what is in the map.
The simplest fix is to create a map of pointers to the object instead of the object itself.
typedef std::map<EntityID, T*> pinstances_map;
T * add(EntityID id) {
T* t = new T();
instances[id] = t;
return t;
};
// initialize as
UnitInfo *info = comp.add(id);
info->x = 10.0;
info->y = 11.0;
// retrieve as
UnitInfos *info = comp.instances[id];
Also, do use an accessor method to get the mapped value, instead of exposing the map object as public. Make the instances variable protected, and add a public get() method.
Edit: This code works fine for me:
#include <map>
#include <iostream>
using namespace std;
template<typename T>
class Component
{
public:
typedef map<long, T*> pinstances_map;
pinstances_map instances;
T * add(long id)
{
T *t = new T();
instances[id] = t;
return t;
}
};
struct UnitInfo
{
float x, y;
};
class LogicComponent: public Component<UnitInfo> {};
int main()
{
LogicComponent comp;
UnitInfo *info = comp.add(99);
info->x = 10.0;
info->y = 11.0;
UnitInfo *info2 = comp.instances[99];
cout << info2->x << " " << info2->y;
return 0;
}
might be that
T add(EntityID id) {
T* t = new T();
instances[id] = *t;
return *t; // return value and map instance are not the same anymore
};
should be
T& add(EntityID id) {
instances[id] = T();
return instances[id];
};
It sounds like you defined your indexing operator as:
template <typename T>
T& Component::operator[]( EntityID id )
{
return instances[id];
}
Or something like that.
The likely unexpected effect of this is that it will automatically insert default-constructed instance of T into the map and then return it for non-exising entries. This is done in std::map so natural assignment syntax like instances[10] = t; works.
The key point here is constness. Define it exactly as above except returning by value and with a const attribute:
template <typename T>
T Component::operator[]( EntityID id ) const
{
return instances[id];
}
This way you will get an exception when you try retrieving by non-existing key. Better yet, just typedef it like bellow and be done with it:
typedef std::map<EntityID,UnitInfos> EntityUnitMap;
Others already mentioned that you don't need to dynamically allocate an object - you store a copy in the container anyway - and that you leak memory when you do that.