I am trying to create a DI container in C++ (for studying purposes). I know about boost DI container option, but I just want to have fun writing one by myself.
I would like that the created container only had one instance per object "registered", so I should apply the Singleton design pattern.
But, what would be the best (idiomatic) way to implement the Singleton Pattern as an in C++20 or, at least, in modern C++ and why?
Do you mean something like this, using meyer's singleton.
(https://www.modernescpp.com/index.php/thread-safe-initialization-of-a-singleton)
I never use singletons that need to be created with new, since their destructor never gets called. With this pattern the destructors do get called when the program terminates.
#include <iostream>
//-----------------------------------------------------------------------------
// create an abstract baseclass (closest thing C++ has to an interface)
struct data_itf
{
virtual int get_value1() const = 0;
virtual ~data_itf() = default;
protected:
data_itf() = default;
};
//-----------------------------------------------------------------------------
// two injectable instance types
struct test_data_container :
public data_itf
{
int get_value1() const override
{
return 0;
}
~test_data_container()
{
std::cout << "test_data_container deleted";
}
};
struct production_data_container :
public data_itf
{
int get_value1() const override
{
return 42;
}
~production_data_container()
{
std::cout << "production_data_container deleted";
}
};
//-----------------------------------------------------------------------------
// meyers threadsafe singleton to get to instances implementing
// interface to be injected.
//
data_itf& get_test_data()
{
static test_data_container test_data;
return test_data;
}
data_itf& get_production_data()
{
static production_data_container production_data;
return production_data;
}
//-----------------------------------------------------------------------------
// object that needs data
class my_object_t
{
public:
explicit my_object_t(const data_itf& data) :
m_data{ data }
{
}
~my_object_t()
{
std::cout << "my_object deleted";
}
void function()
{
std::cout << m_data.get_value1() << "\n";
}
private:
const data_itf& m_data;
};
//-----------------------------------------------------------------------------
int main()
{
auto& data = get_production_data();
my_object_t object{ data };
object.function();
return 0;
}
I am receiveing commands through json, which I insert in to a pipe. For this reason thye must have the same base class.
The pipe is read by a pipe handler, some commands are consumed by the pipe handler, others have to be passed down to a device, which is a member of the pipe handler. I could simply do this:
class Command{};
class HandlerCommand : public Command {
void execute(Handler* h);
};
class DeviceCommand : public Command {
void execute(Device* d);
};
Command* c = pipe.receive();
if (const auto hc = dynamic_cast<const HandlerCommand*>(c)) { hc.execute( **handlerptr** ); }
else if (const auto dc = dynamic_cast<const DeviceCommand*>(c)) { dc.execute( **deviceptr** );}
Device and pipehandler should not have the same base, since they have no common methods, fields, they are conceptually different.
Is there a way to avoid using dynamic cast here. I was thinking maybe there is some neat design pattern for this, but couldn`t quit come up with a better solution.
EDIT: did not derive DeviceCommand and HandlerCommand from command, fixed this.
You cannot use polymorphism of two things which have nothing in common. You will need the same base class/interface: in your case Command. As mentioned above your base class requires a pure virtual function that must be implemented by the derived classes. I will utilize a Command * clone()const prototype, which could be very useful later on. Please introduce a virtual destructor of your base class, otherwise, to track down this memory error could be a pain in the ass. Note, regarding your dynamic_cast the member function execute, must be const. You may try this:
#include <iostream>
#include <vector>
class Handler
{
public:
Handler(){}
};
class Device
{
public:
Device(){}
};
enum class CommandType{Handler,Devise};
class Command
{
public:
virtual ~Command(){}
virtual Command*clone()const = 0;
virtual CommandType getType()const = 0;
};
class HandlerCommand : public Command {
public:
HandlerCommand():Command(){}
void execute(Handler* h) const
{
std::cout << __FUNCTION__<<"\n";
}
HandlerCommand*clone()const { return new HandlerCommand(*this); }
CommandType getType()const { return CommandType::Handler; }
};
class DeviceCommand : public Command{
public:
DeviceCommand():Command(){}
void execute(Device* d)const
{
std::cout << __FUNCTION__<<"\n";
}
DeviceCommand*clone()const { return new DeviceCommand(*this); }
CommandType getType()const { return CommandType::Devise; }
};
int main()
{
Device dev;
Handler handler;
std::vector<Command*> pipe{ new HandlerCommand(), new DeviceCommand() };
while (!pipe.empty())
{
Command* c = pipe.back();
if (c->getType() == CommandType::Handler) { static_cast<const HandlerCommand*>(c)->execute(&handler); }
else if (c->getType() == CommandType::Devise ) { static_cast<const DeviceCommand*>(c)->execute(&dev); }
delete c;
pipe.pop_back();
}
std::cin.get();
}
outputs:
DeviceCommand::execute
HandlerCommand::execute
Version 2.0 using std::variant. You will need at least C++17 to compile this. Note, a single pipe container can exclusively comprise one of the mentioned classes within the variant. So there is no casting anymore, but you will need two pipes. Because of that, I introduced a time stamp variable.
#include <iostream>
#include <vector>
#include <variant>
class Handler
{
public:
Handler() {}
};
class Device
{
public:
Device() {}
};
class HandlerCommand {
int ts;
public:
HandlerCommand(int _ts):ts(_ts) {}
void execute(Handler* h) const
{
std::cout << ts << ": "<< __FUNCTION__ << "\n";
}
int timeStamp()const { return ts; }
};
class DeviceCommand {
int ts;
public:
DeviceCommand(int _ts) :ts(_ts) {}
void execute(Device* d)const
{
std::cout << ts << ": " << __FUNCTION__ << "\n";
}
int timeStamp()const { return ts; }
};
using Command = std::variant<HandlerCommand, DeviceCommand>;
int main()
{
Device dev;
Handler handler;
std::vector<Command> hcPipe{HandlerCommand(2),HandlerCommand(5)};
std::vector<Command> dcPipe{DeviceCommand(1),DeviceCommand(4)};
Command single = DeviceCommand(0);
if (single.index() == 0)
{
std::get<HandlerCommand>(single).execute(&handler);
}
else
{
std::get<DeviceCommand>(single).execute(&dev);
}
while (!hcPipe.empty() || !dcPipe.empty())
{
if (!hcPipe.empty() && (dcPipe.empty() || std::get<HandlerCommand>(hcPipe.front()).timeStamp() < std::get<DeviceCommand>(dcPipe.front()).timeStamp()))
{
std::get<HandlerCommand>(hcPipe.front()).execute(&handler);
hcPipe.erase(hcPipe.begin());
}
else
{
std::get<DeviceCommand>(dcPipe.front()).execute(&dev);
dcPipe.erase(dcPipe.begin());
}
}
std::cin.get();
}
outputs:
0: DeviceCommand::execute
1: DeviceCommand::execute
2: HandlerCommand::execute
4: DeviceCommand::execute
5: HandlerCommand::execute
I have a problem in hand which requires to make a very modular design for different algorithms. For example population based optimization algorithms like genetic algorithm, particle swarm algorithm etc. There are several variants of these algorithms, therefore I planned to make the smaller building blocks as an abstract class and let the specific building block to be plugged in.
For example lets say we have algo1 which can be divided in the following subroutines
algo1
loop
{
sub1 ()
sub2 ()
sub3 ()
}
For this I can create three interfaces which the implementation will override as per their implementation. Therefore
//Sub1Class, Sub2Class, Sub3Class are interfaces/abstract classes
class algo1
{
sub1Class *sub1Obj;
sub2Class *sub2Obj;
sub3Class *sub3Obj;
}
// constructor or setter method to set the implementation
algo1 (Sub1Class *myAlgo1Obj, Sub2Class myAlgo1Obj, Sub3Class myAlgo1Obj)
{
sub1Obj = myAlgo1Obj;
sub2Obj = myAlgo2Obj;
sub3Obj = myAlgo3Obj;
}
doAlgo1
{
loop
{
sub1Obj->algo ();
sub2Obj->algo ();
sub3Obj->algo ();
}
}
This can be done, but all the algorithms uses the attributes of the algo class and there are intermediate variables shared by the algorithms which I do not want to give a getter/setter.
My question is what are the techniques which can be used to manage the shared intermediate variables between the algorithms. I can pass it as the algo method implementation argument, but the number of intermediates and the types may change from one implementation to another. In that case will it be a good idea to create a separate class of temporary variable or make something like friend in cpp? Note that the intermediate results can be large vectors and matrices.
Please let me know if you need more information or clarification.
NOTE: I can possibly omit the variables shared between the algorithms by introducing locals and re-computation, but the algorithms are iterative and computation intensive involving large matrices therefore I want to make object creation and destruction as minimum as possible.
I can propose to use Inverse of Control container to solve your problem.
First you should create several abstract classes to keep it in the container:
class ISubroutineState {
public:
ISubroutineState() = default;
virtual int getVar1() const = 0;
virtual void setVar1(int v1) = 0;
};
class ISubroutineState1 : public ISubroutineState {
public:
virtual std::string getVar2() const = 0;
virtual void setVar2(std::string& v2) = 0;
};
The example of the subroutine state class implementation:
class SubState1 : public ISubroutineState1 {
int var1;
std::string var2;
public:
int getVar1() const {
return var1;
}
std::string getVar2() const {
return var2;
}
void setVar1(int v1) { var1 = v1; }
void setVar2(std::string& v) { var2 = v; }
};
The the IoC container (please note it can be accessed in any way allowed - i used just static pointer for simplicity):
class StateBroker
{
std::map<const char*, ISubroutineState*> *storage;
public:
StateBroker();
template <class S>
void StateBroker::bind(S* state) {
storage->emplace(typeid(S).name(), state);
}
template <class S>
S* StateBroker::get() const {
auto found = storage->find(typeid(S).name());
if (found == storage->end()) return NULL;
return (S*)found->second;
}
~StateBroker();
};
StateBroker* stateBroker;
Now you can implement any type of the subroutines:
class ISubroutine {
public:
virtual void Execute() = 0;
};
class Sub1Class : public ISubroutine {
public:
void Execute()
{
if (stateBroker == NULL)
{
std::cout << "Sub1 called" << std::endl;
}
else {
ISubroutineState1* ss1 = stateBroker->get<ISubroutineState1>();
std::cout << "Sub1 with state called" << std::endl;
ss1->setVar1(1);
ss1->setVar2(std::string("State is changed by Sub1Class"));
std::cout << *static_cast<SubState1*>(ss1) << std::endl;
}
}
};
class Sub2Class : public ISubroutine {
public:
void Execute()
{
if (stateBroker == NULL)
{
std::cout << "Sub2 called" << std::endl;
}
else {
ISubroutineState* ss1 = stateBroker->get<ISubroutineState>();
std::cout << "Sub2 with state called" << std::endl;
ss1->setVar1(2);
std::cout << *static_cast<SubState1*>(ss1) << std::endl;
}
}
};
class Sub3Class : public ISubroutine {
public:
void Execute()
{
if (stateBroker == NULL)
{
std::cout << "Sub3 called" << std::endl;
}
else {
ISubroutineState1* ss1 = stateBroker->get<ISubroutineState1>();
std::cout << "Sub3 with state called" << std::endl;
ss1->setVar1(3);
ss1->setVar2(std::string("State is changed by Sub3Class"));
std::cout << *static_cast<SubState1*>(ss1) << std::endl;
}
}
};
Also please note that subroutine' Execute() can request any type of subroutine state it requires to perform their tasks. It can even create additional state instances (to use in later stage of the algorithm, for example).
Now the main algorithm would look like this:
class Algo {
private:
Sub1Class* sub1;
Sub2Class* sub2;
Sub3Class* sub3;
public:
Algo(Sub1Class* s1, Sub2Class* s2, Sub3Class* s3) : sub1(s1), sub2(s2), sub3(s3){}
void Execute()
{
sub1->Execute();
sub2->Execute();
sub3->Execute();
}
};
... and it's usage (please note it can be used as stateless and as statefull depending on the fact the StateBroker is initialized or not)
Sub1Class s1;
Sub2Class s2;
Sub3Class s3;
std::cout << "Stateless algorithm" << std::endl;
Algo mainAlgo(&s1, &s2, &s3);
mainAlgo.Execute();
stateBroker = new StateBroker();
SubState1* state = new SubState1();
stateBroker->bind<ISubroutineState>(state);
stateBroker->bind<ISubroutineState1>(state);
std::cout << "Statefull algorithm" << std::endl;
Algo statefulAlgo(&s1, &s2, &s3);
statefulAlgo.Execute();
Please note that Algo class doesn't know anything about subroutine states, state broker, etc.; Sub2Class doesn't know about ISubroutineState1; and StateBroker doesn't care about state and subroutine implementation.
BTW, you can review the example project at https://github.com/ohnefuenfter/cppRestudy (VS2015)
Is there any pattern or other nonstandard mechanism for either gcc (4.8) or icc (14.0) that can guarantee the early, safe construction of static locals?
I need a global collection of local static objects references for the purposes of coarse profiling controllable at run-time. I am actively hurt by standard deferred construction (as well as by dealing with locked or redundant thread_local collections), and it would be highly advantageous to have complete point lists at start time.
Any hope to achieve this?
#include <iostream>
#include <deque>
// Really want to build this list before main() started!
struct ProfilePoint;
static std::deque<ProfilePoint *> pps;
// Costly construction, but only ever with literal/constexpr params.
// Templating, etc., also discourages non-local building in reality.
struct ProfilePoint {
ProfilePoint(int id, char const *i) : id_(id), inf_(i) { pps.push_back(this); }
void doStuff() { /* ... */ }
int id_;
char const *const inf_;
};
// Functions like this will be called concurrently in reality.
void bar(int cnt) {
for (int i = 0; i < cnt; ++i) {
// Dropping in a local definition/call should be enough to hook in to system
static ProfilePoint pp(2, "description in a string literal");
pp.doStuff();
/* ... */
}
}
void dump() {
std::cout << "[";
for (ProfilePoint *pp: pps) { std::cout << " " << pp->id_ << ":" << pp->inf_; }
std::cout << " ]" << std::endl;
}
int main() { dump(); bar(5); dump(); } // "[ ]" then "[ 2 ]" in gcc/icc
I've read up on Schwarz Counters and sections 3.6.2 (basic.start.init) / 6.7 (stmt.decl) of the C++11 spec, but I don't have as much knowledge about compiler-specific behavior and haven't been able to find anyone else posting about trying to achieve this trick.
Accepted answer:
As John notes below, all classes (may) have their static members initialized before main(), but given that C++11 §9.4.2/5 [class.static.data] and §9.8/4 [class.local] forbid static data members in local classes, a class that is templated over a local class and has a static data member of that class can have its initialization done at start-time. Quite a brilliant insight, and even more subtle than I first thought!
// John Bandela's solutions (slightly condensed):
template <class TPPDesc> struct PPWrapper_T { static ProfilePoint p; };
template <class TPPDesc>
ProfilePoint PPWrapper_T<TPPDesc>::p(TPPDesc::id(), TPPDesc::desc());
#define PROFILE_POINT(ID, DESC, NAME) \
struct ppdef_##NAME { \
static int id() { return ID; } \
static char const *desc() { return DESC; } \
}; \
static PPWrapper_T<ppdef_##NAME> NAME // semicolon must follow!
// ...
void foo() {
PROFILE_POINT(2, "another_description", pp);
pp.p.doStuff();
}
Note also that using a Meyers singleton method for the collection completes the overall safety of this approach. The collection may have to be locked to guard against concurrent static initializations of the points, however. I still need to check spec to confirm the specification for this and whether the static member initialization is actually forced to be done before main().
Try this
#include <iostream>
#include <deque>
// Really want to build this list before main() started!
struct ProfilePoint;
static std::deque<ProfilePoint *> pps;
// Costly construction, but only ever with literal/constexpr params.
// Templating, etc., also discourages non-local building in reality.
struct ProfilePoint {
ProfilePoint(int id, char const *i) : id_(id), inf_(i) { pps.push_back(this); }
void doStuff() { /* ... */ }
int id_;
char const *const inf_;
};
template<class IdDescription>
struct ProfilePoint_{
static ProfilePoint p;
};
template<class IdDescription>
ProfilePoint ProfilePoint_<IdDescription>::p( IdDescription::id(), IdDescription::description() );
#define PROFILE_POINT(theid,thedescription) \
struct ppdef_static_class{ \
static int id(){ return theid; } \
static const char* description(){ return thedescription; } \
};\
static ProfilePoint_<ppdef_static_class>
// Functions like this will be called concurrently in reality.
void bar(int cnt) {
for (int i = 0; i < cnt; ++i) {
// Dropping in a local definition/call should be enough to hook in to system
PROFILE_POINT(2, "description is a string literal") pp;
pp.p.doStuff();
/* ... */
}
}
void dump() {
std::cout << "[";
for (ProfilePoint *pp : pps) { std::cout << " " << pp->id_ << ":" << pp->inf_; }
std::cout << " ]" << std::endl;
}
int main() { dump(); bar(5); dump(); } // Does what you want
This works for MSVC 2013 and ideone http://ideone.com/Z3n1U0
This does require use of macro and to call doStuff() you have to do .p.doStuff(). You also cannot have more than 1 profile point in a function (but this can easily be fixed).
This works by defining a local class that is used as a parameter to a template class that has a static member. By referencing that template in the function, you force the compiler to instantiate the static member of the template.
Let me know if you have any questions about this technique.
You might do it like:
#include <iostream>
#include <deque>
#include <memory>
#include <map>
class ProfilePoint
{
public:
typedef unsigned Identifier;
private:
struct Data {
Identifier id;
const char* information;
unsigned count;
Data(Identifier id, const char* information)
: id(id), information(information), count(0)
{}
};
public:
static void dump();
const char* information() const { return m_data.information; }
Identifier id() const { return m_data.id; }
ProfilePoint(const char* information)
: m_data(*get_data(0, information))
{}
void apply() const {
++m_data.count;
}
private:
static Data* get_data(Identifier, const char* information);
Data& m_data;
};
ProfilePoint::Data* ProfilePoint::get_data(Identifier id, const char* information) {
typedef std::deque<Data> StaticData;
StaticData static_data;
if( ! information) return &static_data[id];
else {
static_data.push_back(Data(static_data.size(), information));
for(auto d: static_data)
std::cout << d.information << std::endl;
return &static_data.back();
}
return 0;
}
void ProfilePoint::dump() {
std::cout << "dump" << std::endl;
Data* data;
for(Identifier i = 0; (data = get_data(i, 0)); ++i) {
std::cout
<< "Profile Point: " << data->information
<< ", Count: " << data->count << std::endl;
}
}
namespace {
ProfilePoint pf("Function");
void f() {
pf.apply();
pf.apply();
pf.apply();
ProfilePoint::dump();
}
} // namespace
int main()
{
f();
return 0;
}
This maintains a single instance of a profile point container in a function and initialize each profile point during translation unit initialization.
Below I have attempted to write a sudo code for the Observer pattern when observers wish to observe different items.
Ignore the syntax errors. I wish to know if this is the correct way to implement this. If not, please suggest better ways.
// Used by the subject for keeping a track of what items the observer wants to observe
typedef struct observerListStruct
{
bool getTemperatureUpdate;
bool getHumidityUpdate;
bool getPressureUpdate;
observer's-function pointer's address;
};
// Subject's class
class weatherData
{
public:
// Observers will call this function to register themselves. The function pointer will point to the function which will get called when updates are available.
void registerObservers (observer obj, observer's-FunctionPointer)
{
// This observer's function returns which items to observe.
char* f = obj.returnItemsToObserve ();
if f[0] = `1`
observerListStruct.getTemperatureUpdate = true;
}
void unregisterObservers (observer obj) {}
private:
vector <observerListStruct> observerList;
float temperature;
float humidity;
float pressure;
void notifyObservers () {}
float getTemperature () {}
float getHumidity () {}
float getPressure () {}
} weatherDataObject;
// Base class for observers containing common functions
class observers
{
char ItemsToObserve [3] = {1, 2, 3};
// This observer's function returns which items to observe. Default - return all items
virtual char* returnItemsToObserve ()
{
return ItemsToObserve;
}
};
class observerDisplayElementCurrentConditions : public observers
{
char ItemsToObserve [3] = {1, 2};
char* returnItemsToObserve ()
{
return ItemsToObserve;
}
// this function will be used as a function pointer for getting updates
void getUpdatesAndDisplayWeatherData (float, float) {}
};
A more pattern oriented solution (but without function pointers) could be the following. You could parametrize the WeatherObserver-Class to get only the values, you want.
#include <list>
#include <iostream>
class Observable; //forward declaration
//Base class for all observers
class Observer {
friend class Observable; //allow access to observedSubject
protected:
Observable *observedSubject;
public:
virtual void update(){};
};
//Base class for all observables
class Observable {
private:
std::list<Observer * const> m_registeredObservers;
public:
~Observable()
{
//delete the observers
std::list<Observer * const>::iterator it = m_registeredObservers.begin();
while (it != m_registeredObservers.end())
{
delete *it;
it = m_registeredObservers.erase(it);
}
}
void addObserver(Observer * const _pObserver)
{
_pObserver->observedSubject = this;
m_registeredObservers.push_back(_pObserver);
}
void removeObserver(Observer * const _pObserver)
{
m_registeredObservers.remove(_pObserver);
delete _pObserver;
}
void notifyObservers()
{
std::list<Observer * const>::iterator it = m_registeredObservers.begin();
while (it != m_registeredObservers.end())
{
(*it)->update();
it++;
}
}
};
//Concrete Observable
class WeatherData : public Observable {
private:
float temperature;
float humidity;
float pressure;
public:
WeatherData(): temperature(0), humidity(0), pressure(0)
{};
float getTemperature () const
{
return temperature;
}
float getHumidity () const
{
return humidity;
}
float getPressure () const
{
return pressure;
}
void setTemperature(float _temperature)
{
if (temperature != _temperature)
{
temperature = _temperature;
notifyObservers();
}
}
void setHumidity(float _humidity)
{
if (humidity != _humidity)
{
humidity = _humidity;
notifyObservers();
}
}
void setPressure(float _pressure)
{
if (pressure != _pressure)
{
pressure = _pressure;
notifyObservers();
}
}
};
//Concrete implementation of an weather observer
class WeatherObserver : public Observer
{
public:
WeatherObserver():Observer(){};
void update()
{
WeatherData* pWeatherPtr = static_cast<WeatherData*>(observedSubject);
if (pWeatherPtr != 0)
{
float actHumidity = pWeatherPtr->getHumidity();
float actPressure = pWeatherPtr->getPressure();
float actTemperature = pWeatherPtr->getTemperature();
//do something with the data
std::cout << "WeatherObserver update" << std::endl;
std::cout << "Temperature : " << actTemperature << std::endl;
std::cout << "Humidity : " << actHumidity << std::endl;
std::cout << "Pressure : " << actPressure << std::endl;
}
}
};
int main()
{
WeatherData weatherData;
Observer * pObserver = new WeatherObserver();
weatherData.addObserver(pObserver);
weatherData.setHumidity(100);
weatherData.setTemperature(100);
}
#include <algorithm>
#include <vector>
class WeatherFlags
{
public:
WeatherFlags()
: mask_(0)
{}
union {
struct {
unsigned int temperature_ : 1;
unsigned int humidity_ : 1;
unsigned int pressure_ : 1;
};
unsigned int mask_;
};
};
class WeatherData;
class WeatherEvent
{
public:
WeatherEvent(WeatherData* data, WeatherFlags const& flags)
: data_(data)
, flags_(flags)
{}
double getTemperature() const;
WeatherData* data_;
WeatherFlags flags_;
};
class WeatherListener
{
public:
virtual ~WeatherListener() = 0;
virtual void onWeatherUpdate(WeatherEvent& e) = 0;
};
inline WeatherListener::~WeatherListener() {}
class WeatherListenerEntry
{
public:
WeatherListenerEntry()
: listener_(0)
{}
WeatherListenerEntry(WeatherListener* listener, WeatherFlags const& flags)
: listener_(listener)
, flags_(flags)
{}
WeatherListener* listener_;
WeatherFlags flags_;
};
class WeatherData
{
public:
WeatherData();
void addListener(WeatherListener* listener, WeatherFlags const& flags);
void removeListener(WeatherListener* listener);
void notify(WeatherFlags const& flags);
double getTemperature() const { return temperature_; }
private:
typedef std::vector<WeatherListenerEntry> Listeners;
Listeners listeners_;
double temperature_;
};
WeatherData::WeatherData()
: temperature_(0)
{}
void WeatherData::addListener(WeatherListener* listener, WeatherFlags const& flags)
{
// TODO Could maybe check for the addition of duplicates here...
listeners_.push_back(WeatherListenerEntry(listener, flags));
}
void WeatherData::removeListener(WeatherListener* listener)
{
struct ListenerEquals {
WeatherListener* listener_;
ListenerEquals(WeatherListener* listener)
: listener_(listener)
{}
bool operator()(WeatherListenerEntry const& e) const {
return (e.listener_ == listener_);
}
};
listeners_.erase(
std::remove_if(listeners_.begin(), listeners_.end(), ListenerEquals(listener)),
listeners_.end());
}
void WeatherData::notify(WeatherFlags const& flags)
{
WeatherEvent evt(this, flags);
for (Listeners::iterator i = listeners_.begin(); i != listeners_.end(); ++i)
{
if (0 != (i->flags_.mask_ & flags.mask_)) {
i->listener_->onWeatherUpdate(evt);
}
}
}
double
WeatherEvent::getTemperature() const
{
return data_->getTemperature();
}
#include <iostream>
class WeatherObserverStdout : public WeatherListener
{
public:
void observe(WeatherData& data) {
WeatherFlags flags;
flags.temperature_ = true; // interested in temperature only.
data.addListener(this, flags);
}
virtual void onWeatherUpdate(WeatherEvent& e);
};
void
WeatherObserverStdout::onWeatherUpdate(WeatherEvent& e)
{
double temp = e.getTemperature();
std::cout << "Temperatrure: " << temp << std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
WeatherData wdata;
WeatherObserverStdout obs;
obs.observe(wdata);
WeatherFlags flags;
wdata.notify(flags);
flags.temperature_ = true;
wdata.notify(flags);
return 0;
}
I think it is easier, and more scalable, to define a set of event types that each observer can listen to. Then you register the observer to listen to that particular event type. The observed then keeps a list of observers registered for each event, and notifies them if and when the event occurs. Using a combination of std::function, std::bind (or boost equivalents), it is easy to register callbacks for a given event type. You could put the callbacks in a map of event type to callback.
For example, something along these lines (almost pseudo-code, has not been tested)
class Publisher {
public :
void subscribe(const std::string& event,
std::function<void(double)> callback) {
m_subscribers[s].push_back(callback);
}
void publish(const std::string& event) const {
for (auto& f : m_subscribers[event]) f( some double );}
void event(const std::string& event) const { publish(event);}
private:
// map of event types (here simply strings) to list of callbacks
std::map<std::string&,
std::list<std::function<void(const std::string&)>>> m_subscribers;
};
struct Foo {
void foo(double x) {
std::cout << "Foo received message: " << x << "\n";
}
};
struct Bar {
void bar(double x) {
std::cout << "Bar received message: " << x << "\n";
}
};
int main() {
Publisher pub;
Foo f0;
Foo f1;
Bar bar0;
pub.subscribe("RED", std::bind(&Foo::foo, &foo0, _1));
pub.subscribe("GREEN", std::bind(&Foo::foo, &foo1, _1));
pub.subscribe("WHITE", std::bind(&Foo::foo, &foo1, _1));
pub.subscribe("RED", std::bind(&Bar::bar, &bar0, _1));
pub.subscribe("BLUE", std::bind(&Bar::bar, &bar0, _1));
pub.subscribe("MAGENTA", std::bind(&Bar::bar, &bar0, _1));
// trigger a "GREEN" event
pub.event("GREEN");
}
Here, the observers (or subscribers) register to some events, represented by strings here, and their registered callbacks get called when this event happens. In the example above I manually trigger an event to illustrate the mechanism.
This event-callback mechanism allows to decouple the actual items from the callback action. The Observed (or publisher) knows what parameter to pass the callback for a given event, and which callbacks to call, so the observers are not dependent on the internal data of the observed object.
I write a lot of C++ code and needed to create an Observer for some game components I was working on. I needed something to distribute "start of frame", "user input", etc., as events in the game to interested parties.
I also wanted more granularity in the events that could be handled. I have a lot of little things that go off...I don't need to have the parts that are interested in resetting for the next frame worried about a change in the user input.
I also wanted it to be straight C++, not dependent on the platform or a specific technology (such as boost, Qt, etc.) because I often build and re-use components (and the ideas behind them) across different projects.
Here is the rough sketch of what I came up with as a solution:
The Observer is a singleton with keys (enumerated values, not strings; this is a speed tradeoff since the keys are not searched hashed, but it means no easy "string" names and you have to define them ahead of time) for Subjects to register interest in. Because it is a singleton, it always exists.
Each subject is derived from a common base class. The base class has an abstract virtual function Notify(...) which must be implemented in derived classes, and a destructor that removes it from the Observer (which it can always reach) when it is deleted.
Inside the Observer itself, if Detach(...) is called while a Notify(...) is in progress, any detached Subjects end up on a list.
When Notify(...) is called on the Observer, it creates a temporary copy of the Subject list. As it iterates over it, it compare it to the recently detached. If the target is not on it, Notify(...) is called on the target. Otherwise, it is skipped.
Notify(...) in the Observer also keeps track of the depth to handle cascading calls (A notifies B, C, D, and the D.Notify(...) triggers a Notify(...) call to E, etc.)
This is what the interface ended up looking like:
/*
The Notifier is a singleton implementation of the Subject/Observer design
pattern. Any class/instance which wishes to participate as an observer
of an event can derive from the Notified base class and register itself
with the Notiifer for enumerated events.
Notifier derived classes MUST implement the notify function, which has
a prototype of:
void Notify(const NOTIFIED_EVENT_TYPE_T& event)
This is a data object passed from the Notifier class. The structure
passed has a void* in it. There is no illusion of type safety here
and it is the responsibility of the user to ensure it is cast properly.
In most cases, it will be "NULL".
Classes derived from Notified do not need to deregister (though it may
be a good idea to do so) as the base class destructor will attempt to
remove itself from the Notifier system automatically.
The event type is an enumeration and not a string as it is in many
"generic" notification systems. In practical use, this is for a closed
application where the messages will be known at compile time. This allows
us to increase the speed of the delivery by NOT having a
dictionary keyed lookup mechanism. Some loss of generality is implied
by this.
This class/system is NOT thread safe, but could be made so with some
mutex wrappers. It is safe to call Attach/Detach as a consequence
of calling Notify(...).
*/
class Notified;
class Notifier : public SingletonDynamic<Notifier>
{
public:
typedef enum
{
NE_MIN = 0,
NE_DEBUG_BUTTON_PRESSED = NE_MIN,
NE_DEBUG_LINE_DRAW_ADD_LINE_PIXELS,
NE_DEBUG_TOGGLE_VISIBILITY,
NE_DEBUG_MESSAGE,
NE_RESET_DRAW_CYCLE,
NE_VIEWPORT_CHANGED,
NE_MAX,
} NOTIFIED_EVENT_TYPE_T;
private:
typedef vector<NOTIFIED_EVENT_TYPE_T> NOTIFIED_EVENT_TYPE_VECTOR_T;
typedef map<Notified*,NOTIFIED_EVENT_TYPE_VECTOR_T> NOTIFIED_MAP_T;
typedef map<Notified*,NOTIFIED_EVENT_TYPE_VECTOR_T>::iterator NOTIFIED_MAP_ITER_T;
typedef vector<Notified*> NOTIFIED_VECTOR_T;
typedef vector<NOTIFIED_VECTOR_T> NOTIFIED_VECTOR_VECTOR_T;
NOTIFIED_MAP_T _notifiedMap;
NOTIFIED_VECTOR_VECTOR_T _notifiedVector;
NOTIFIED_MAP_ITER_T _mapIter;
// This vector keeps a temporary list of observers that have completely
// detached since the current "Notify(...)" operation began. This is
// to handle the problem where a Notified instance has called Detach(...)
// because of a Notify(...) call. The removed instance could be a dead
// pointer, so don't try to talk to it.
vector<Notified*> _detached;
int32 _notifyDepth;
void RemoveEvent(NOTIFIED_EVENT_TYPE_VECTOR_T& orgEventTypes, NOTIFIED_EVENT_TYPE_T eventType);
void RemoveNotified(NOTIFIED_VECTOR_T& orgNotified, Notified* observer);
public:
virtual void Reset();
virtual bool Init() { Reset(); return true; }
virtual void Shutdown() { Reset(); }
void Attach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
// Detach for a specific event
void Detach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
// Detach for ALL events
void Detach(Notified* observer);
/* The design of this interface is very specific. I could
* create a class to hold all the event data and then the
* method would just have take that object. But then I would
* have to search for every place in the code that created an
* object to be used and make sure it updated the passed in
* object when a member is added to it. This way, a break
* occurs at compile time that must be addressed.
*/
void Notify(NOTIFIED_EVENT_TYPE_T, const void* eventData = NULL);
/* Used for CPPUnit. Could create a Mock...maybe...but this seems
* like it will get the job done with minimal fuss. For now.
*/
// Return all events that this object is registered for.
vector<NOTIFIED_EVENT_TYPE_T> GetEvents(Notified* observer);
// Return all objects registered for this event.
vector<Notified*> GetNotified(NOTIFIED_EVENT_TYPE_T event);
};
/* This is the base class for anything that can receive notifications.
*/
class Notified
{
public:
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, const void* eventData) = 0;
virtual ~Notified();
};
typedef Notifier::NOTIFIED_EVENT_TYPE_T NOTIFIED_EVENT_TYPE_T;
NOTE: The Notified class has a single function, Notify(...) here. Because the void* is not type safe, I created other versions where notify looks like:
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, int value);
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, const string& str);
Corresponding Notify(...) methods were added to the Notifier itself. All these used a single function to get the "target list" then called the appropriate function on the targets. This works well and keeps the receiver from having to do ugly casts.
This seems to work well. The solution is posted on the web here along with the source code. This is a relatively new design, so any feedback is greatly appreciated.
My two cents...
Classic (Gang of Four) implementation of Observer pattern notifies observer on changes in any property of the subject. In your question you want to register observer to particular properties, not to a subject as a whole. You can move Observer pattern one level down and take properties as concrete subjects and define their observers (per property) but there is one nicer way to solve this problem.
In C# Observer pattern is implemented through events and delegates. Delegates represent event handlers - functions that should be executed when an event is fired. Delegates can be added (registered) or removed(unregistered) from events.
In C++, functors act as delegates - they can store all necessary information to call some global function or class method in a different context. Events are collections of (registered) functors and when event is raised (called) it basically goes through that list and calls all functors (see Publisher::publish method in juanchopanza's solution).
I tried to implement C++ version of events and delegates and use them in modified Observer pattern which could be applied in your case. This is what I came up with:
#include <list>
#include <iostream>
#include <algorithm>
// use base class to resolve the problem of how to put into collection objects of different types
template <typename TPropertyType>
struct PropertyChangedDelegateBase
{
virtual ~PropertyChangedDelegateBase(){};
virtual void operator()(const TPropertyType& t) = 0;
};
template <typename THandlerOwner, typename TPropertyType>
struct PropertyChangedDelegate : public PropertyChangedDelegateBase<TPropertyType>
{
THandlerOwner* pHandlerOwner_;
typedef void (THandlerOwner::*TPropertyChangeHandler)(const TPropertyType&);
TPropertyChangeHandler handler_;
public:
PropertyChangedDelegate(THandlerOwner* pHandlerOwner, TPropertyChangeHandler handler) :
pHandlerOwner_(pHandlerOwner), handler_(handler){}
void operator()(const TPropertyType& t)
{
(pHandlerOwner_->*handler_)(t);
}
};
template<typename TPropertyType>
class PropertyChangedEvent
{
public:
virtual ~PropertyChangedEvent(){};
void add(PropertyChangedDelegateBase<TPropertyType>* const d)
{
std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), d);
if(it != observers_.end())
throw std::runtime_error("Observer already registered");
observers_.push_back(d);
}
void remove(PropertyChangedDelegateBase<TPropertyType>* const d)
{
std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), d);
if(it != observers_.end())
observers_.remove(d);
}
// notify
void operator()(const TPropertyType& newValue)
{
std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = observers_.begin();
for(; it != observers_.end(); ++it)
{
(*it)->operator()(newValue);
}
}
protected:
std::list<PropertyChangedDelegateBase<TPropertyType>* const> observers_;
};
// class that owns concrete subjects
class PropertyOwner1
{
int property1_;
float property2_;
public:
PropertyChangedEvent<int> property1ChangedEvent;
PropertyChangedEvent<float> property2ChangedEvent;
PropertyOwner1() :
property1_(0),
property2_(0.0f)
{}
int property1() const {return property1_;}
void property1(int n)
{
if(property1_ != n)
{
property1_ = n;
std::cout << "PropertyOwner1::property1(): property1_ set to " << property1_ << std::endl;
property1ChangedEvent(property1_);
}
}
float property2() const {return property2_;}
void property2(float n)
{
if(property2_ != n)
{
property2_ = n;
std::cout << "PropertyOwner1::property2(): property2_ set to " << property2_ << std::endl;
property2ChangedEvent(property2_);
}
}
};
// class that owns concrete subjects
class PropertyOwner2
{
bool property1_;
double property2_;
public:
PropertyChangedEvent<bool> property1ChangedEvent;
PropertyChangedEvent<double> property2ChangedEvent;
PropertyOwner2() :
property1_(false),
property2_(0.0)
{}
bool property1() const {return property1_;}
void property1(bool n)
{
if(property1_ != n)
{
property1_ = n;
std::cout << "PropertyOwner2::property1(): property1_ set to " << property1_ << std::endl;
property1ChangedEvent(property1_);
}
}
double property2() const {return property2_;}
void property2(double n)
{
if(property2_ != n)
{
property2_ = n;
std::cout << "PropertyOwner2::property2(): property2_ set to " << property2_ << std::endl;
property2ChangedEvent(property2_);
}
}
};
// class that observes changes in property1 of PropertyOwner1 and property1 of PropertyOwner2
struct PropertyObserver1
{
void OnPropertyOwner1Property1Changed(const int& newValue)
{
std::cout << "\tPropertyObserver1::OnPropertyOwner1Property1Changed(): \n\tnew value is: " << newValue << std::endl;
}
void OnPropertyOwner2Property1Changed(const bool& newValue)
{
std::cout << "\tPropertyObserver1::OnPropertyOwner2Property1Changed(): \n\tnew value is: " << newValue << std::endl;
}
};
// class that observes changes in property2 of PropertyOwner1 and property2 of PropertyOwner2
struct PropertyObserver2
{
void OnPropertyOwner1Property2Changed(const float& newValue)
{
std::cout << "\tPropertyObserver2::OnPropertyOwner1Property2Changed(): \n\tnew value is: " << newValue << std::endl;
}
void OnPropertyOwner2Property2Changed(const double& newValue)
{
std::cout << "\tPropertyObserver2::OnPropertyOwner2Property2Changed(): \n\tnew value is: " << newValue << std::endl;
}
};
int main(int argc, char** argv)
{
PropertyOwner1 propertyOwner1;
PropertyOwner2 propertyOwner2;
PropertyObserver1 propertyObserver1;
PropertyObserver2 propertyObserver2;
// register observers
PropertyChangedDelegate<PropertyObserver1, int> delegate1(&propertyObserver1, &PropertyObserver1::OnPropertyOwner1Property1Changed);
propertyOwner1.property1ChangedEvent.add(&delegate1);
PropertyChangedDelegate<PropertyObserver2, float> delegate2(&propertyObserver2, &PropertyObserver2::OnPropertyOwner1Property2Changed);
propertyOwner1.property2ChangedEvent.add(&delegate2);
PropertyChangedDelegate<PropertyObserver1, bool> delegate3(&propertyObserver1, &PropertyObserver1::OnPropertyOwner2Property1Changed);
propertyOwner2.property1ChangedEvent.add(&delegate3);
PropertyChangedDelegate<PropertyObserver2, double> delegate4(&propertyObserver2, &PropertyObserver2::OnPropertyOwner2Property2Changed);
propertyOwner2.property2ChangedEvent.add(&delegate4);
propertyOwner1.property1(1);
propertyOwner1.property2(1.2f);
propertyOwner2.property1(true);
propertyOwner2.property2(3.4);
// unregister PropertyObserver1
propertyOwner1.property1ChangedEvent.remove(&delegate1);
propertyOwner2.property1ChangedEvent.remove(&delegate3);
propertyOwner1.property1(2);
propertyOwner1.property2(4.5f);
}
Output:
PropertyOwner1::property1(): property1_ set to 1
PropertyObserver1::OnPropertyOwner1Property1Changed():
new value is: 1
PropertyOwner1::property2(): property2_ set to 1.2
PropertyObserver2::OnPropertyOwner1Property2Changed():
new value is: 1.2
PropertyOwner2::property1(): property1_ set to 1
PropertyObserver1::OnPropertyOwner2Property1Changed():
new value is: 1
PropertyOwner2::property2(): property2_ set to 3.4
PropertyObserver2::OnPropertyOwner2Property2Changed():
new value is: 3.4
PropertyOwner1::property1(): property1_ set to 2
PropertyOwner1::property2(): property2_ set to 4.5
PropertyObserver2::OnPropertyOwner1Property2Changed():
new value is: 4.5
Each observer is registered with a particular property and when notified, each observer knows exactly who is the owner of the property and what's property's new value.