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()};
Related
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.
The below class is meant to be a top-layer class which brings all the benefits of nlohman::json but offers additional functions.
#include <nlohmann/json.hpp>
class Other { /* ... */ };
class AbstractData : public nlohmann::json
{
public:
AbstractData (const nlohmann::json& json) : nlohmann::json(json) { }
Other createOther(const char* key) { /* create Other class using key */ }
std::string toString() { /* convert to string */ }
/* etc. */
};
But I ran into issues when using operator[]. By default we have
AbstractData a;
auto& val = a["some_key"]; // val is nlohman::json::value_type&
and thus val loses all the extra functions.
When we provide a class function operator[]
const AbstractData& AbstractData::operator[](const char* key) const
{
return nlohmann::json::operator[](key);
}
then
AbstractData a;
auto& val = a["some_key"]; // val is AbstractData&
works as expected. But in order to achieve this, the copy constructor AbstractData (const nlohmann::json& json) is called (which is very inefficient for large objects). And this defeats the purpose of returning a reference in the first place.
I've seen questions like this one Add a method to existing C++ class in other file but they didn't offer help with my specific problem.
Any advice?
I would drop inheritance and wrap de data completely.
Why? Because the moment you need a second AbstractData, you will have to hold and potentially copy the json value. If you wrap the json data instead of using inheritance, then you can act as a view over json data.
class AbstractData {
// view over json
nlohmann::json const* _json_ptr;
auto json() -> nlohmann::json const& {
return *_json_ptr;
}
public:
AbstractData(nlohmann::json const& json) : nlohmann::json(&json) {}
Other createOther(const char* key) {
/* create Other class using key */
}
std::string toString() {}
auto operator[](const char* key) const -> AbstractData {
return AbstractData{&(json()[key])};
}
};
As you can see you can safely return by value, since your class only holds a pointer to your value and is cheap to copy.
If you also want your class to be the owner, you can store the json as a const shared pointer:
class AbstractData {
using root_t = std::shared_ptr<nlohmann::json const>;
// owner of the json root.
root_t _root;
// view over json
nlohmann::json const* _json_ptr;
auto json() -> nlohmann::json const& {
return *_json_ptr;
}
AbstractData(nlohmann::json const& json, root_t root) :
_root(root), _json_ptr(&json) {}
public:
struct new_root_t {} static constexpr new_root{};
AbstractData(new_root_t, nlohmann::json json) :
_root{std::make_shared<nlohmann::json const>(std::move(json))}, _json_ptr{_root.get()} {}
auto operator[](const char* key) const -> AbstractData {
// always pass down the root, so someone will own it
return AbstractData{json()[key], _root};
}
};
Live example
As a side note, you had undefined behaviour:
// return by reference?
const AbstractData& AbstractData::operator[](const char* key) const {
// construct a new, local value
// the local value is destroyed then returned
return nlohmann::json::operator[](key);
}
I strongly suggest to return by value here.
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.
class ZombieLand : public Singleton<ZombieLand>
{
DECLARE_SINGLETON(ZombieLand);
public:
MachineState* world[19][19];
bool map[19][19];
MachineState* getField(int x, int y)
{
return world[x][y];
}
void setWorld(MachineState state)
{
world[state.x][state.y] = &state;
map[state.x][state.y] = true;
}
};
struct MachineState
{
template <typename MachineTraits>
friend class Machine;
enum Facing { UP, RIGHT, DOWN, LEFT};
MachineState()
: m_ProgramCounter(1)
, m_ActionsTaken(0)
, m_Facing(UP)
, m_Test(false)
, m_Memory(nullptr)
,x(0)
,y(0)
,point1(25, 10)
,point2(10, 40)
,point3(40, 40)
{ }
int m_ProgramCounter;
int m_ActionsTaken;
Facing m_Facing;
bool m_Test;
bool m_occupied;
int x;
int y;
Point point1;
Point point2;
Point point3;
int GetActionsPerTurn() const throw() { return m_ActionsPerTurn; }
int GetMaxMemory() const throw() {return m_MaxMemory; }
bool GetTruth() const throw() { return m_InfectOnAttack; }
void setPoint(Point p1, Point p2, Point p3)
{
point1=p1;
point2=p2;
point3=p3;
}
};
I later call the getField function by doing
MachineState *Field1 = ZombieLand::get().getField(state.x, state.y-1 );
The problem is that when i try to access a member by doing Field1->getTruth() it's returning me the address of the pointer rather than the actual value(false or true). I don't understand why this is happening
template <class T>
class Singleton
{
private:
static T* _instance;
protected:
Singleton() {}
public:
static T& get()
{
if (_instance)
{
return *_instance;
}
else
{
_instance = new T();
return *_instance;
}
}
};
if(ZombieLand::get().map[state.x+2][state.y] == true)
{
MachineState *field3 = ZombieLand::get().getField(state.x+2, state.y);
std::cout<<"FOUND FIELD"<<Field3->getTruth();
}
when this if statement becomes true it prints "FOUND FIELD 0246" onto my console
As we do not have the signature of both get and getField it is difficult to tell.
But perhaps try
*(ZombieLand::get().getField(state.x, state.y-1 ))
To get the value that the pointer is pointing to.
EDIT
It helps to read the code i.e.
MachineState * world [19][19];
is a 2D array of pointers. Nowhere in this code is those pointers given a value so as it stands you are just lucky that the thing does not just die.
Therefore,
MachineState *getField(int x, int y)
{
return world[x][y];
}
As specified by the signature of the function as well!
But where in this code do you give the pointer a value or meaning?
OK, now I think you've finally posted the code that has the problem
class ZombieLand : public Singleton<ZombieLand>
{
DECLARE_SINGLETON(ZombieLand);
public:
MachineState* world[19][19];
bool map[19][19];
MachineState* getField(int x, int y)
{
return world[x][y];
}
void setWorld(MachineState state)
{
world[state.x][state.y] = &state;
map[state.x][state.y] = true;
}
};
This is undefined behaviour because you are saving the pointer to a local variable state. The state variable gets destroyed after you have exited the setWorld function, so your world array is just holding pointers to destroyed objects, That's why you have garbage values.
Rewrite this class without pointers.
class ZombieLand : public Singleton<ZombieLand>
{
DECLARE_SINGLETON(ZombieLand);
public:
MachineState world[19][19];
bool map[19][19];
MachineState* getField(int x, int y)
{
return &world[x][y];
}
void setWorld(const MachineState& state)
{
world[state.x][state.y] = state;
map[state.x][state.y] = true;
}
};
Pointers are almost always a bad idea, you should try to write code without them.
Got there in the end at least.
void setWorld(MachineState state)
{
world[state.x][state.y] = &state;
map[state.x][state.y] = true;
}
You are initializing the contents of the world array with the memory address of a local variable on the stack that goes out of scope and is no longer valid after setWorld() exits, leaving the array pointing at invalid MachineState objects. When getField() is called later on, you get random data from the current call stack.
If you want the array to point to external MachineState instances, you need to pass them in by reference instead of by value so you get the address of the original object and not a temporary anymore:
void setWorld(MachineState &state)
{
world[state.x][state.y] = &state;
map[state.x][state.y] = true;
}
Otherwise, change the array to not hold pointers anymore:
class ZombieLand : public Singleton<ZombieLand>
{
DECLARE_SINGLETON(ZombieLand);
public:
MachineState world[19][19];
bool map[19][19];
MachineState* getField(int x, int y)
{
return &world[x][y];
}
void setWorld(const MachineState &state)
{
world[state.x][state.y] = state;
map[state.x][state.y] = true;
}
};
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();
}
};