I am trying to implement observer pattern into my project.
Imagine simple a class method
const Buffer * data() const
{
if (m_data)
return m_data;
// read some data from input
m_data = fstream.read(1000);
// subscribe to our buffer
m_data->Subscribe(this);
return m_data;
}
This method is used to read input data, but the operation could be time consuming, it is therefore delayed.
Class Buffer is simple wrapper above std::vector, which notifies observers, when it's data being altered.
The containing class needs to be notified, when Buffer data changes.
However, since this method is marked as const, I am unable to subscribe to the Buffer.
I was able to figure out 3 solutions:
1. Cast away const-ness
// subscribe to our buffer
m_data->Subscribe(const_cast<Object*>(this));
I am not sure, whether this is correct, but it works.
2. Change const-ness of notification method and observers
vector<const IModifyObserver*> m_observers;
void Subscribe(const IModifyObserver* observer);
void Unsubscribe(const IModifyObserver* observer)
virtual void ObserveeChanged(IModifyObservable*) const override
{
m_dirty = true;
}
This one has a downfall, if I need to change properties they all have to be mutable and all functions I call must be const, which also does not make any sense.
3. Remove const from everywhere
Buffer * data();
bool Equals(Object& other);
Buffer* m_data;
This would most probably mean, that I would have to remove const from whole solution, since I can't event call Equals for two different const objects.
How to properly solve this problem?
Full Code:
#include <vector>
using namespace std;
class IModifyObservable;
// class for receiving changed notifications
class IModifyObserver
{
public:
virtual void ObserveeChanged(IModifyObservable* observee) = 0;
virtual ~IModifyObserver() = 0;
};
// class for producing changed notifications
class IModifyObservable
{
public:
// Add new subscriber to notify
void Subscribe(IModifyObserver* observer)
{
m_observers.push_back(observer);
}
// Remove existing subscriber
void Unsubscribe(IModifyObserver* observer)
{
for (auto it = m_observers.begin(); it != m_observers.end(); ++it) {
if (observer == *it) {
m_observers.erase(it);
break;
}
}
}
// Notify all subscribers
virtual void OnChanged()
{
auto size = m_observers.size();
for (decltype(size) i = 0; i < size; ++i) {
m_observers[i]->ObserveeChanged(this);
}
}
virtual ~IModifyObservable() = 0;
private:
vector<IModifyObserver*> m_observers;
};
IModifyObserver::~IModifyObserver() {}
IModifyObservable::~IModifyObservable() {}
// Example class implementing IModifyObservable
class Buffer : public IModifyObservable
{
private:
vector<char> m_data;
};
// Example class implementing IModifyObserver
class Object : public IModifyObserver
{
public:
// Both share implementation
//Buffer * data();
const Buffer * data() const
{
// Just read some data
//m_data = fstream.read(1000);
// Subscribe to our buffer
m_data->Subscribe(this);
return m_data;
}
virtual void ObserveeChanged(IModifyObservable*) override
{
m_dirty = true;
}
// This is just for example, why do I need const data method
bool Equals(const Object& other) const { return data() == other.data();
}
private:
mutable Buffer* m_data = new Buffer();
bool m_dirty;
};
int main()
{
Object obj1;
Object obj2;
auto data1 = obj1.data();
auto data2 = obj2.data();
bool equals = (obj1.Equals(obj2));
}
What gets in the way here is you deferred reading. Without this optimisation the right way would be to separate constant and non-constant methods:
const Buffer * data() const
{
return m_data;
}
void InitializeData()
{
// Just read some data
m_data = fstream.read(1000);
// Subscribe to our buffer
m_data->Subscribe(this);
}
Then optimize it the way you want:
const Buffer * data() const
{
if(m_data == nullptr)
const_cast<Object*>(this)->InitializeData();
return m_data;
}
And you don't need m_data to mutable anymore.
BTW. To make this deferred initialization work you should initialize m_data member with nullptr. Otherwise this object will be created while constructing and your if(m_data) will be always true.
UPD
So here is another solution to your problem
class Object : public IModifyObserver
{
public:
Object()
: m_data(nullptr)
, m_dataInitialized(false)
// ...
{
m_data = new Buffer(); // << Create buffer here
m_data->Subscribe(this); // << And subscribe right away
}
const Buffer * data() const
{
if(!m_dataInitialized) // << Initialize if needed
{
// Set data here
m_data->setData(fstream.read(1000)); // << Probably you want to suppress notifications here
m_dataInitialized = true;
}
return m_data;
}
// ...
private:
mutable Buffer* m_data;
mutable bool m_dataInitialized; // << Added another flag to see if data was initialized
// ...
};
I took the liberty of refactoring your code, I couldn't see where the initial call to data() would happen in your example, but I imagine it is called in a 2-phase way (construct -> then call method). Sticking with the simple rule..
#include <algorithm>
#include <memory>
#include <vector>
using namespace std;
class IModifyObservable;
// class for receiving changed notifications
class IModifyObserver
{
public:
virtual void ObserveeChanged(IModifyObservable* observee) = 0;
virtual ~IModifyObserver() = default;
};
// class for producing changed notifications
class IModifyObservable
{
public:
// This method modifies state - so non-const
void Subscribe(IModifyObserver* observer)
{
observers_.push_back(observer);
}
// This method modifies state - so non-const
void Unsubscribe(IModifyObserver* observer)
{
observers_.erase(find(begin(observers_), end(observers_), observer));
}
// Again as the internal state of the observer is modified, this is non-const
virtual void OnChanged()
{
for (auto observer : observers_) {
observer->ObserveeChanged(this);
}
}
virtual ~IModifyObservable() = default;
private:
vector<IModifyObserver*> observers_;
};
// Example class implementing IModifyObservable
class Buffer : public IModifyObservable
{
vector<char> data_;
};
// Example class implementing IModifyObserver
class Object : public IModifyObserver
{
public:
// The first call to the non-cost version triggers the lazy load...
const Buffer* data()
{
if (!data_) {
data_ = make_unique<Buffer>();
// Now start the read operation
// :
// Subscribe, I imagine you only want to do this once?
data_->Subscribe(this);
}
return data_.get();
}
// Calls to const version returns what's there...
const Buffer* data() const
{
return data_.get();
}
// This has to be non-cost as the internal state is being modified
void ObserveeChanged(IModifyObservable*) override
{
dirty_ = true;
}
// Operator uses const versions, which will use const methods
friend
bool operator==(const Object& lhs, const Object& rhs) {
if (lhs.data() && rhs.data()) {
}
return false;
}
private:
unique_ptr<Buffer> data_;
bool dirty_ = false;
};
int main()
{
Object obj1;
Object obj2;
auto data1 = obj1.data();
auto data2 = obj2.data();
bool equals = obj1 == obj2;
}
There are no hacks, it should just work...
Avoid to register in the a getter, register in initialization:
class Object : public IModifyObserver
{
public:
Object() { m_data.Subscribe(this); }
const Buffer* data() const { return m_data; }
Buffer* data() { return m_data; }
void ObserveeChanged(IModifyObservable*) override { m_dirty = true; }
private:
Buffer m_data;
bool m_dirty = false;
};
With lazy initialization, it becomes:
class Object : public IModifyObserver
{
public:
Object() { m_data.Subscribe(this); }
Buffer& data()
{
if (!m_data.is_initialized()) { m_data.initialize(); }
return m_data;
}
const Buffer& data() const
{
if (!m_data.is_initialized()) { m_data.initialize(); }
return m_data;
}
void ObserveeChanged(IModifyObservable*) override { m_dirty = true; }
private:
mutable Buffer m_data;
bool m_dirty = false;
};
Demo
Related
I created sets of functions using the type-erasure design pattern:
Encodable: encode(), decode()
Printable: print()
If I overload these functions with MyStruct1 and MyStruct2, I'll be able to wrap these types in the type-erasure wrappers Encodable and Printable and indirectly call those functions using the wrappers functions and store MyStruct1 and MyStruct2 in a heterogeneous container like std::vector<Encodable>.
My problem arised when I wanted to use these objects both as an Encodable and a Printable or when I wanted to convert one to the other.
#include <cstdint>
#include <utility>
#include <memory>
#include <vector>
class Encodable {
private:
struct EncodableConcept {
virtual ~EncodableConcept() = default;
virtual std::vector<uint8_t> _encode() const = 0;
virtual bool _decode(std::vector<uint8_t> const& byteVector) = 0;
virtual std::unique_ptr<EncodableConcept> clone() const = 0;
};
template<typename EncodableT>
struct EncodableModel : public EncodableConcept {
EncodableModel(EncodableT inst) : _inst{std::move(inst)}
{}
std::vector<uint8_t> _encode() const override {
return encode(_inst);
}
bool _decode(std::vector<uint8_t> const& byteVector) override {
return decode(_inst, byteVector);
}
std::unique_ptr<EncodableConcept> clone() const override {
return std::make_unique<EncodableModel>(*this);
}
EncodableT _inst;
};
friend std::vector<uint8_t> encode(Encodable const& inst) {
return inst.pimpl->_encode();
}
friend bool decode(Encodable & inst, std::vector<uint8_t> const& byteVector) {
return inst.pimpl->_decode(byteVector);
}
public:
template<typename EncodableT>
Encodable(EncodableT inst)
: pimpl{std::make_unique<EncodableModel<EncodableT>>(std::move(inst))}
{}
Encodable(Encodable const& other)
: pimpl(other.pimpl->clone())
{}
Encodable& operator=(Encodable const& other) {
// Copy-and-swap idiom
Encodable tmp(other);
std::swap(pimpl, tmp.pimpl);
return *this;
}
// Move is not implemented to prevent the pimpl to be nullptr after move operation.
// Upon move the copy constructor or the copy assignment operator is going to be called.
private:
std::unique_ptr<EncodableConcept> pimpl;
};
class Printable {
private:
struct PrintableConcept {
virtual ~PrintableConcept() = default;
virtual void _print() const = 0;
virtual std::unique_ptr<PrintableConcept> clone() const = 0;
};
template<typename PrintableT>
struct PrintableModel : public PrintableConcept {
PrintableModel(PrintableT inst) : _inst{std::move(inst)}
{}
void _print() const override {
print(_inst);
}
std::unique_ptr<PrintableConcept> clone() const override {
return std::make_unique<PrintableModel>(*this);
}
PrintableT _inst;
};
friend void print(Printable const& inst) {
inst.pimpl->_print();
}
public:
template<typename PrintableT>
Printable(PrintableT inst)
: pimpl{std::make_unique<PrintableModel<PrintableT>>(std::move(inst))}
{}
Printable(Printable const& other)
: pimpl(other.pimpl->clone())
{}
Printable& operator=(Printable const& other) {
// Copy-and-swap idiom
Printable tmp(other);
std::swap(pimpl, tmp.pimpl);
return *this;
}
// Move is not implemented to prevent the pimpl to be nullptr after move operation.
// Upon move the copy constructor or the copy assignment operator is going to be called.
private:
std::unique_ptr<PrintableConcept> pimpl;
};
struct MyStruct1 {
MyStruct1(int x) : x{x} {}
int x;
};
std::vector<uint8_t> encode(MyStruct1 const& inst) {
std::vector<uint8_t> byteVector;
// ...
return byteVector;
}
bool decode(MyStruct1 & inst, std::vector<uint8_t> const& byteVector) {
// ...
return true; // Success
}
void print(MyStruct1 const& inst) {
printf("MyStruct1{%d}\n", inst.x);
}
struct MyStruct2 {
MyStruct2(float y) : y{y} {}
float y;
};
std::vector<uint8_t> encode(MyStruct2 const& inst) {
std::vector<uint8_t> byteVector;
// ...
return byteVector;
}
bool decode(MyStruct2 & inst, std::vector<uint8_t> const& byteVector) {
// ...
return true; // Success
}
void print(MyStruct2 const& inst) {
printf("MyStruct2{%f}\n", inst.y);
}
std::vector<Encodable> readFromSomewhere() {
std::vector<Encodable> readEncodables;
// Read from file, socket, etc...
readEncodables = {MyStruct1{1}, MyStruct2{2.2}, MyStruct1{3}, MyStruct2{4.4}};
return readEncodables;
}
int main(int argc, char** argv) {
std::vector<Encodable> readEncodables = readFromSomewhere();
// TODO: How can I print readEncodables using the overloaded print functions?
// For example:
for (Encodable const& obj : readEncodables) {
// print(obj); // Compilation error (thanks god)
}
// TODO: How can I convert an Encodable to a Printable object?
std::vector<Printable> convertedPrintables;
for (Encodable const& obj : readEncodables) {
// convertedPrintables.emplace_back(obj); // Compilation error (thanks god)
// print(*convertedPrintables.crbegin());
}
return 0;
}
How can I easily convert an Encodable to a Printable and vice versa?
Can I somehow directly use an Encodable as a Printable if the print() function is overloaded for the given type?
My only (bad) solution is to create a templated get() function in the wrappers to unwrap the contained object run-time. If the type of the template argument matches the object the unwrap succeeds and I can rewrap it into a Printable or just directly use the overloaded print() free function.
template<typename EncodableT>
EncodableT* get() const {
EncodableModel<EncodableT>* modelPtr = dynamic_cast<EncodableModel<EncodableT>*> pimpl.get());
if (modelPtr == nullptr) return nullptr;
return &modelPtr->_inst;
}
However the usage of this function would be rather ugly and inconvenient:
for (Encodable const& obj : readEncodables) {
auto* ptr1 = obj.get<MyStruct1>();
if (ptr1 != nullptr) {
print(*ptr1);
continue;
}
auto* ptr2 = obj.get<MyStruct2>();
if (ptr2 != nullptr) {
print(*ptr2);
continue;
}
// ...
}
This could be made a bit nicer by storing std::type_index the wrappers, but I'd still have create if-else or switch statements for each type for calling a simple print() free function...
I'm working on an arduino project, this is relevant since there's no support for STL nor dynamic allocation on arduino natively. I've noticed that a lot of classes I'm writing do nothing on construction, but have an .init() method that actually initializes any resources. This is because that way the class can be initialized in the global scope, and then when the setup function runs, actual initialization happens as .init() is called there.
For example:
const portn_t en=A5, rs=A4, d4=A0, d5=A1, d6=A2, d7=A3;
// making room for that object in the global scope
// this way it can be both used in ``setup()`` and ``loop()``
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
lcd.begin(16, 2); // Doing the actual initialization
}
void loop() {
lcd.clear();
lcd.write("Hello world!");
delay(500);
}
This works fine for classes that are designed with an init or begin method. This design pattern is common in most Arduino libraries, but for classes that don't implement this I'm currently using this as a workaround:
Button& get_btn_up() {
// The Button class actually does initialization at construcion
static Button bt(2, true);
return bt;
}
Button& get_btn_enter() {
static Button bt(3, true);
return bt;
}
Button& get_btn_down() {
static Button bt(4, true);
return bt;
}
void setup() {
// Initializes all the ``Button`` objects
get_btn_up();
get_btn_enter();
get_btn_down();
}
void loop() {
auto up = get_btn_up();
if (up.just_pressed()) {
...
}
...
}
Which I don't believe is an optimal solution, as there's a lot of boiler plate just to achieve something that could be done with new and some unique pointers.
Because of this I attempted making a DelayedInit container class, that would hold the required memory for the object in a union and handle its lifetime
template<typename T>
union MemoryOf {
uint8_t memory [sizeof(T)];
T obj;
};
template<typename T>
struct DelayedInit {
private:
MemoryOf<T> memory{.memory={ 0 }};
bool is_set = false;
public:
T& get() const {
memory.obj;
}
DelayedInit() {}
~DelayedInit() {
if (is_set)
get().~T();
}
T* operator->() const {
return &get();
}
T& operator*() {
is_set = true;
return get();
}
const T& operator*() const {
return get();
}
explicit operator bool() const {
return is_set;
}
};
This implementation is broken at the time, as it locks the arduino up whenever I try to call any methods of the boxed class. Here's how it's supposed to be used
DelayedInit<Button> up, enter, down;
void setup() {
*up = Button(2, true);
*enter= Button(3, true);
*down = Button(4, true);
}
void loop() {
if (up->just_pressed()) { // Locks up the arduino
...
}
...
}
I'm guessing there's some memory management error in the code that I'm not aware of. What errors are present in the DelayedInit implementation? Is there a better approach at solving this issue?
This is the solution I ended up with. .init emulates the pattern that most classes in the arduino libraries use, without actually splitting the init logic in two methods. There's definitely room for improvement, but this works for global variables.
#pragma once
#include <new>
template<typename T>
union MemoryOf {
uint8_t memory [sizeof(T)];
T obj;
MemoryOf() : memory{ 0 } {};
~MemoryOf() {};
};
// Only tested with global variables
// so there might be bugs in the cleanup bits
template<typename T>
struct DelayedInit {
private:
MemoryOf<T> memory;
bool is_set = false;
public:
const T& get() const {
return memory.obj;
}
T& get() {
return memory.obj;
}
void remove() {
get().~T();
}
DelayedInit() {};
~DelayedInit() {
if (is_set)
remove();
}
template<typename ...Args>
inline void init(Args ...args) {
if (is_set) {
remove();
}
new (&memory.memory) T(args...); // == &memory.obj
is_set = true;
}
T* operator->() {
return &get();
}
const T* operator->() const {
return &get();
}
T& operator*() {
return get();
}
const T& operator*() const {
return get();
}
explicit operator bool() const {
return is_set;
}
};
Usage:
#include "delayed_init.hpp"
DelayedInit<Button> up, enter, down;
void setup() {
up.init(2, true);
enter.init(3, true);
down.init(4, true);
}
void loop() {
if (up->just_pressed()) {
...
}
...
}
Thanks to EOF for suggesting the use of placement new!
In C++ is there a way, using raw pointers or otherwise to trigger some action when the pointed to object changes?
Scenario:
class A
{
double var;
B var2 {&var};
}
class B
{
double* pVar;
B (double* _var ) { pVar = _var};
}
I have functions inside class B that will get called whenever member variable var changes value. At the moment I would need these functions to be public so they can be called manually from class A, this could be achieved by using a setter for var. If I wanted to keep the function inside class B private (as it is called by other events internal to class B) what are my options?
This is an example of the observer pattern.
So what you need is to trigger a function call to another object
when the value of your object is changed through a setter method.
#include <functional>
#include <iostream>
//-----------------------------------------------------------------------------
// the class with the member variable that can change
// and to which another class can react.
// This is a simple example where only one "callback" function
// can be registered. In the typical observer pattern
// there can be multiple callbacks registered.
class Observee
{
public:
// set notification function to a function that does nothing
// "null strategy pattern"
Observee() :
m_notify_observer_fn{ [](int) {} }
{
}
// let another object pass in a function that will be called
// when the value is changed
void OnValueChanged(std::function<void(int)> notify_observer_fn)
{
m_notify_observer_fn = notify_observer_fn;
}
// to change the member value AND notify the other object
// that the value has changed we need a setter function.
void set_value(int value)
{
// check if the value really has changed
if (m_value != value)
{
// set the member value
m_value = value;
// then notify the observer of the new value
// by calling the notification function
m_notify_observer_fn(m_value);
}
}
private:
std::function<void(int)> m_notify_observer_fn;
int m_value{};
};
//-----------------------------------------------------------------------------
// The class that wants to get a notification when the value
// of the other class changes (role is an Observer)
class Observer
{
public:
explicit Observer(Observee& observee)
{
// Set the callback in the observee to the OnValueChanged
// function of this object (the function passed is called a lambda funtion)
observee.OnValueChanged([this](int value)
{
OnValueChanged(value);
});
}
private:
void OnValueChanged(int value)
{
std::cout << "Value changed to " << value << "\n";
}
};
//-----------------------------------------------------------------------------
int main()
{
// make instances of both classes.
Observee observee;
Observer observer{ observee };
// now set the value
// this will change the member in observee
// and then call the method in the observer for you
observee.set_value(42);
return 0;
}
Question : If I wanted to keep the function inside class B private (as it is called by other events internal to class B) what are my options?
You can call a private function of class B while coding class A using friend attribute.
class B
{
friend class A;
private:
void foo() { std::cout << "using foo." << std::endl; }
};
class A
{
private:
B b;
public:
void bar(){ b.foo(); }
};
int main()
{
A a;
a.bar();
return 0;
}
About the callback to be call when a double variable change its value:
No you can't do it with a raw pointer.
You got at least two ways of doing it.
The first way is what you outlined : use a setter function.
The second is to make a class that own the value and that overloading operator= is able to call the callback.
I'll sketch something here to make you understand better:
template<class T>
class Owner{
using FuncType = std::function<void(Owner<T>&)>;
public:
Owner(){}
Owner(const T& init){
_var = init;
}
Owner(const Owner<T>& init){
_var = init;
}
operator T(){
return _var;
}
auto& operator =(const T& rvalue){
_var = rvalue;
_on_change();
return *this;
}
auto& operator =(const Owner<T>& rvalue){
_var = rvalue;
_on_change();
return *this;
}
const T& get() const { //don't make it non const or
//you will lose ownership to value of _var
return _var;
}
void set(const T& val){
_var = val;
_on_change();
}
void set(const Owner<T>& val){
_var = val;
_on_change();
}
void set_handler(FuncType func)
{
_func = func;
}
private:
void _on_change(){
if(_func)
_func(*this);
}
private:
T _var{};
FuncType _func{};
};
int main()
{
Owner<double> var{};
var.set_handler([](Owner<double>& ch){
std::cout << "Value changed: " << (double) ch << std::endl;
});
var = 1.0;
return 0;
}
I am creating a Signal and Slot system with a design like this:
There is the signal and slot classes
struct timeDoubleEvent
{
public:
timeDoubleEvent(const std::string& dataName)
:
dataName(dataName)
{}
const std::string& getDataName() const { return dataName; }
Event<hydraPtr<DataHandler::timeDouble>> update;
void fire(const hydraPtr<DataHandler::timeDouble>& timeDouble) const { update(timeDouble); }
private:
const std::string dataName;
};
class timeDoubleSlot
{
public:
timeDoubleSlot(const std::string& dataName)
:
dataName(dataName)
{}
const std::string& getDataName() const { return dataName; }
virtual void onEvent(const hydraPtr<DataHandler::timeDouble>& timeDouble) = 0;
private:
const std::string dataName;
};
The slot would eventually differ for various cases, so I am creating derived class of it nested inside something:
class BaseClass
{
// forward declaration
class timePriceSlot;
public:
BaseClass(const std::string& name,
const std::vector<hydraPtr<EventHandler::timeDoubleEvent>>& dataEventVector,
const size_t& warmUpLength)
:
name(name),
dataSlotVector(initializeDataSlotVector(dataEventVector)),
warmUpLength(warmUpLength),
dataStorage(initializeDataStorage(dataEventVector)),
timeStorage(initializeTimeStorage(dataEventVector))
{}
private:
const std::vector<hydraPtr<timePriceSlot>> dataSlotVector;
const std::vector<hydraPtr<timePriceSlot>> initializeDataSlotVector(const std::vector<hydraPtr<EventHandler::timeDoubleEvent>>&);
const bool& checkAllDataReceived(const std::string& dataName);
class timePriceSlot : public EventHandler::timeDoubleSlot
{
public:
timePriceSlot(const std::string& dataName,
BaseClass& parent)
:
timeDoubleSlot(dataName),
parent(parent)
{}
void onEvent(const hydraPtr<DataHandler::timeDouble>& timeDouble);
BaseClass& getParent() const { return parent; }
private:
BaseClass& parent;
};
};
(only showing the relevant bits) In particular, the signal-slot connection is done like this:
const std::vector<hydraPtr<BaseClass::timePriceSlot>> BaseClass::initializeDataSlotVector(
const std::vector<hydraPtr<EventHandler::timeDoubleEvent>>& dataEventVector)
{
std::vector<hydraPtr<BaseClass::timePriceSlot>> output(dataEventVector.size());
for (size_t i = 0; i < dataEventVector.size(); ++i)
{
EventHandler::timeDoubleEvent thisTimeDoubleEvent = (*dataEventVector[i]);
std::shared_ptr<BaseClass::timePriceSlot> thisTimePriceSlot = std::make_shared<BaseClass::timePriceSlot>(dataEventVector[i]->getDataName(), *this);
output[i] = thisTimePriceSlot;
thisTimeDoubleEvent.update.connect([&](hydraPtr<DataHandler::timeDouble>& timeDouble) { (*thisTimePriceSlot).onEvent(timeDouble); });
}
return output;
}
I am calling the function with a client program like this:
const std::string stockName = "BBH";
EventHandler::timeDoubleEvent event1(stockName);
std::vector<hydraPtr<EventHandler::timeDoubleEvent>> eventVector(1);
eventVector[0] = std::make_shared<EventHandler::timeDoubleEvent>(stockName);
const hydraPtr<Signal::DerivedClass> myMA = std::make_shared<Signal::DerivedClass>(stockName + "_MA", eventVector, 10);
const std::vector<hydraPtr<DataHandler::PriceTimeSeriesDataStruct>> myData = getAggregatedData();
const std::vector<double> priceVectorCopy = myData[0]->getPriceVector();
std::vector<double>::const_iterator it_d;
const std::vector<std::string> timeVectorCopy = myData[0]->getDateTimeVector();
std::vector<std::string>::const_iterator it_s;
for (it_d = priceVectorCopy.begin(), it_s = timeVectorCopy.begin();
it_d != priceVectorCopy.end(); it_d++, it_s++)
{
const hydraPtr<DataHandler::timeDouble> timeDoubleTemp = std::make_shared<DataHandler::timeDouble>(stockName, (*it_s), (*it_d));
event1.fire(timeDoubleTemp);
}
(DerivedClass is derived from BaseClass, with a different implementation of one function not relevant here) However, I found that even though there is no build or run time error, nothing happens upon the event fire. In fact, the onEvent function is never visited. Have I done something wrong? Thanks in advance.
The problem was in this line
thisTimeDoubleEvent.update.connect([&](hydraPtr<DataHandler::timeDouble>& timeDouble) { (*thisTimePriceSlot).onEvent(timeDouble); });
Both the event and the slot should be pointers, not dereferenced values.
I have a simple class which consists of a void pointer and an int (this is some sort of a boost::Variant educational project).
I also have a working copy constructor and a destructor.
But what grinds my gears is, how I would accomplish something like this:
Container cont1("some value"); //simple construction
Container cont2;
cont2.createLink(cont1); //this should initialize members with a reference (or something alike)
std::cout<<cont1; //yields "some value"
cont2.set(20); //setting this container should update the original container too, since I initialized with a reference (or smth alike)
std::cout<<cont1; //yields 20
This is the simplified version of the class:
class Container {
public:
Container(){}
Container(const std::string &val){var.type = STRING; var.data = new std::string(val);}
Container(int val){ /* same for int */}
Container(const Container &val){ /* do a memory copy */}
void set(int val){ /* set the value if type matches, otherwise allocate a new pointer */}
void set(const std::string &val){ /* the same as for int */}
void createLink(const Container &val){ /* somehow assign a reference or whatsoever */}
private:
typedef struct VAR {
int type = 0;
void *data = NULL; }
VAR var;
}
If I set the value of cont2 to a string (i.e. the same data type it holds at the moment), everything is fine, because the set would not allocate a new pointer and rather assign a new value.
But how do I make sure the pointer of cont1 updates if I assign a different value to cont2 and therefore have to allocate a new pointer?
Would I need something like shared_pointer?
Thanks for any insight!
EDIT:
I changed to function name to make it more clear what should happen.
There is a solution that only involves straight OO. You could create an interface for your variant type, and use double indirection to the variant instance to allow linked containers to share the same variant instance.
The reason double indirection is required is because of the way you want the set() method to automatically allocate a new variant instance if the new type doesn't match the original type. If we simply shared a pointer to the variant from both containers, then after set() creates a new variant instance, each container would be referring to different instances again.
To get around that, we can use a pointer to a pointer to a variant in the container instead.
Here is a possible way to define your variant interface, and how it could be subclassed:
typedef std::ostream Out;
struct BadType {};
struct Var {
virtual ~Var () = default;
virtual Out & print (Out &os) { return os << "(BadType)"; }
virtual void set (int) { throw BadType(); }
virtual void set (const std::string &) { throw BadType(); }
};
struct VarInteger : Var {
int data;
VarInteger (int v) : data(v) {}
Out & print (Out &os) { return os << data; }
void set (int v) throw() { data = v; }
};
struct VarString : Var {
std::string data;
VarString (const std::string &v) : data(v) {}
Out & print (Out &os) { return os << data; }
void set (const std::string &v) throw() { data = v; }
};
Here is how you could define your pointer to pointer, and how they could be initialized:
typedef std::shared_ptr<Var> VarPtr;
std::shared_ptr<VarPtr> varptr_;
static VarPtr make_var () { return std::make_shared<Var>(); }
static VarPtr make_var (int v) { return std::make_shared<VarInteger>(v); }
static VarPtr make_var (const std::string &v) {
return std::make_shared<VarString>(v);
}
VarPtr & var () { return *varptr_; }
const VarPtr & var () const { return *varptr_; }
Container () : varptr_(std::make_shared<VarPtr>(make_var())) {}
Container (int v) : varptr_(std::make_shared<VarPtr>(make_var(v))) {}
Container (const std::string &v)
: varptr_(std::make_shared<VarPtr>(make_var(v))) {}
And here is how your set() methods and createLink() method could be implemented.
void set (int v) {
try { var()->set(v); }
catch (BadType) { var() = make_var(v); }
}
void set (const std::string &v) {
try { var()->set(v); }
catch (BadType) { var() = make_var(v); }
}
void createLink (const Container &val) { varptr_ = val.varptr_; }
Demo
How about the following. Of course createLink cannot not take a const reference so I made it to take a non-const pointer.
class Container {
const int STRING = 0x0000001;
const int INT = 0x0000002;
const int LINK = 0x8000000;
public:
...
void set(int val){...}
void set(const std::string &val)
{
if (var.type == LINK)
{
reinterpret_cast<Container*>(var.data)->set(val);
}
else
...
}
void createLink(Container* val)
{
var.data = val;
var.type = LINK;
}
private:
typedef struct VAR {
int type = 0;
void *data = NULL;
};
VAR var;
};
There are a some important points to think about - relative lifetimes of the link and the linked is the most obvious one.