Library managing lifetime of objects, use smart pointers or raw? - c++

Rolling my own GUI library for a side-project. Refactoring to use smart pointers; however, I ran into an issue.
I'm aware that you do not want to to use smart pointers across DLL boundaries for obvious reasons. But I feel dirty using 'new' in application code. See below:
// MYFINANCEAPP.H
class MyFinanceApp : public Application
{
MyFinanceApp() : mMainWindow(make_unique<Window>())
{
mMainWindow->AddControl(*(new Button("testButton")));
}
private:
std::unique_ptr<Window> mMainWindow;
};
// WINDOW.H
class Window
{
public:
void AddControl(Control& control) //QUESTION: HOW DO I GET SMART POINTER HERE???
{
mControls.emplace_back(&control)
}
private:
std::vector<std::unique_ptr<Control>> mControls; //Want to use smart pointers so I am not responsible for managing...
};
Am I better to use C++98 style and semantics and handle it myself. Obviously I do not want to pass smart pointers across the interface boundary (i.e. AddControl), but I don't want to be responsible for handling the lifetime of the controls.
Additionally, I feel really dirty using new Button("testButton").

A reminder that ABI issues can be circumvented if you simply make a guarantee that you won't release a DLL compiled on a different compiler/version/platform than the primary executable.
At any rate, regarding your interface design:
void AddControl(Control& control) {
mControls.emplace_back(&control)
}
You've got a problem here, because
Control is Polymorphic (or at least seems to be based on what code you provided) which means you have to pass by reference or by pointer to get a "complete" object, but
You don't want to expose an interface where the user has to maintain raw pointers, even briefly, before passing them along to your application.
This is how I would design around this problem:
class Window {
public:
void AddControl(std::unique_ptr<Control> control) {//Note we're passing by value!
mControls.emplace_back(std::move(control));
}
private:
std::vector<std::unique_ptr<Control>> mControls;
};
Then, in your application:
class MyFinanceApp : public Application {
public:
MyFinanceApp() : mMainWindow(make_unique<Window>()) {
mMainWindow->AddControl(std::make_unique<Button>("testButton"));
}
private:
std::unique_ptr<Window> mMainWindow;
};
Note that this doesn't necessarily stop your users from doing something stupid, like
std::unique_ptr<Window> window_ptr = std::make_Unique<Window>();
Button * button = new Button("This won't be properly deleted!");
window_ptr->AddControl(std::unique_ptr<Button>{button});
delete button; //Whoops!
... But there wasn't necessarily anything stopping them from doing that in the first place.
An alternative is to have a "Factory" associated with the Controls. We'd first need to make a modification to AddControl:
Control & AddControl(std::unique_ptr<Control> control) {
mControls.emplace_back(std::move(control));
return *mControls.back();
}
struct ControlFactory {
static Button & create_button(Window & window, std::string button_text) {
std::unique_ptr<Button> button_ptr = std::make_unique<Button>(button_text);
Button & ref = *button_ptr;
window.AddControl(std::move(button_ptr));
//ref will NOT be invalidated, because the object will still exist in memory,
//in the same location in memory as before. Only the unique_ptr will have changed.
return ref;
}
};
And then you'd simply need to change the access modifiers on all your Control subclasses to not allow direct access to their constructors by end-user programmers. Something like this would probably suffice:
class Button : public Control {
/*...*/
protected:
Button() {/*...*/}
Button(std::string text) {/*...*/}
friend class ControlFactory; //Allows ControlFactory to access, even though access is protected.
};
Then your users would be storing references on their end, which is safer than pointers, though it does mean you need to guarantee that those references never outlive the application itself.

Related

c++ particle system inheritance

i'm creating particle system and i want to have possibility to choose what kind of object will be showing on the screen (like simply pixels, or circle shapes). I have one class in which all parameters are stored (ParticleSettings), but without those entities that stores points, or circle shapes, etc. I thought that i may create pure virtual class (ParticlesInterface) as a base class, and its derived classes like ParticlesVertex, or ParticlesCircles for storing those drawable objects. It is something like that:
class ParticlesInterface
{
protected:
std::vector<ParticleSettings> m_particleAttributes;
public:
ParticlesInterface(long int amount = 100, sf::Vector2f position = { 0.0,0.0 });
const std::vector<ParticleSettings>& getParticleAttributes() { return m_particleAttributes; }
...
}
and :
class ParticlesVertex : public ParticlesInterface
{
private:
std::vector<sf::Vertex> m_particleVertex;
public:
ParticlesVertex(long int amount = 100, sf::Vector2f position = { 0.0,0.0 });
std::vector<sf::Vertex>& getParticleVertex() { return m_particleVertex; }
...
}
So... I know that i do not have access to getParticleVertex() method by using polimorphism. And I really want to have that access. I want to ask if there is any better solution for that. I have really bad times with decide how to connect all that together. I mean i was thinking also about using template classes but i need it to be dynamic binding not static. I thought that this idea of polimorphism will be okay, but i'm really need to have access to that method in that option. Can you please help me how it should be done? I want to know what is the best approach here, and also if there is any good answer to that problem i have if i decide to make that this way that i show you above.
From the sounds of it, the ParticlesInterface abstract class doesn't just have a virtual getParticleVertex because that doesn't make sense in general, only for the specific type ParticlesVertex, or maybe a group of related types.
The recommended approach here is: Any time you need code that does different things depending on the actual concrete type, make those "different things" a virtual function in the interface.
So starting from:
void GraphicsDriver::drawUpdate(ParticlesInterface &particles) {
if (auto* vparticles = dynamic_cast<ParticlesVertex*>(&particles)) {
for (sf::Vertex v : vparticles->getParticleVertex()) {
draw_one_vertex(v, getCanvas());
}
} else if (auto* cparticles = dynamic_cast<ParticlesCircle*>(&particles)) {
for (CircleWidget& c : cparticles->getParticleCircles()) {
draw_one_circle(c, getCanvas());
}
}
// else ... ?
}
(CircleWidget is made up. I'm not familiar with sf, but that's not the point here.)
Since getParticleVertex doesn't make sense for every kind of ParticleInterface, any code that would use it from the interface will necessarily have some sort of if-like check, and a dynamic_cast to get the actual data. The drawUpdate above also isn't extensible if more types are ever needed. Even if there's a generic else which "should" handle everything else, the fact one type needed something custom hints that some other future type or a change to an existing type might want its own custom behavior at that point too. Instead, change from a thing code does with the interface to a thing the interface can be asked to do:
class ParticlesInterface {
// ...
public:
virtual void drawUpdate(CanvasWidget& canvas) = 0;
// ...
};
class ParticlesVertex {
// ...
void drawUpdate(CanvasWidget& canvas) override;
// ...
};
class ParticlesCircle {
// ...
void drawUpdate(CanvasWidget& canvas) override;
// ...
};
Now the particles classes are more "alive" - they actively do things, rather than just being acted on.
For another example, say you find ParticlesCircle, but not ParticlesVertex, needs to make some member data updates whenever the coordinates are changed. You could add a virtual void coordChangeCB() {} to ParticlesInterface and call it after each motion model tick or whenever. With the {} empty definition in the interface class, any class like ParticlesVertex that doesn't care about that callback doesn't need to override it.
Do try to keep the interface's virtual functions simple in intent, following the Single Responsibility Principle. If you can't write in a sentence or two what the purpose or expected behavior of the function is in general, it might be too complicated, and maybe it could more easily be thought of in smaller steps. Or if you find the virtual overrides in multiple classes have similar patterns, maybe some smaller pieces within those implementations could be meaningful virtual functions; and the larger function might or might not stay virtual, depending on whether what remains can be considered really universal for the interface.
(Programming best practices are advice, backed by good reasons, but not absolute laws: I'm not going to say "NEVER use dynamic_cast". Sometimes for various reasons it can make sense to break the rules.)

Is static casting a good design in my situation?

I use game state manager (intro, main menu, gameplay etc) from here. However there is one problem. A very minimalistic example:
class cApp //manages the states and gives them access to window
{
public:
cApp (RenderWindow & ref) : window(ref) {}
void changeState(cState *); //these function realy doesn't matter
void update();
void draw();
RenderWindow & window; //the same as in the article, this class not only manages state but gives them access to window etc
private:
std::vector <cState *> states;
}
The state:
class cState
{
public:
cState(cApp * ptr) : app(ptr) {}
virtual void update() = 0;
virtual void draw() = 0;
protected:
cApp * app;
}
So far everything is good. The problem is this is the part of basic framework. So the cApp is only very basic and gives access only to window. However there may be the case where the user wants to use networking in his game. Network engine isn't a part of single state so it must be at the more global (that means, cApp) level.
So the user does:
class cNetworkedApp : public cApp
{
public:
cNetworkedApp(RenderWindow & ref1, NetworkEngine & ref2)
: networking(ref2), cApp(ref1)
NetworkEngine & networking; //initialized in cNetworkedApp constructor
}
class CharacterCreationState : public cState
{
CharacterCreationState(cApp * ptr) : cState(ptr) {}
//implement pure virtual functions
void draw()
{}
void update()
{
//THE PROBLEM
//the state needs to access the network engine so casting is required
cNetworkedApp * ptr = static_cast<cNetworkedApp*>(app))
ptr->networking.sendSomething();
}
}
The only obvious solution is to include everything what may be possible in cApp, however as I said this is a framework. Of course some engines like physics engine or sound engine are things which you put into a state so that's not problem, but things like networking system must be the one object available for all states. And not every app uses it.
Do I need to redesign this code or is it okay?
Your cApp may keep with it a named list of a polymorphic type Engine, ie map<string,Engine*>, then, your user may ask the cApp if it has a given engine.
NetworkEngine would be a subclass of the pure abstract Engine.
Update
When dealing with a pointer that I you are sure that it is of the given specialized type, you should use static_cast, when you wanna query if the pointer can be casted to a type you should use dynamic_cast.
I, myself, have a safer approach for the first case, I use an assertion to guarantee that the type can be casted and use the static_cast in normal code:
Engine* fetchedEngine = cApp.fetch("network");
assert( dynamic_cast<NetworkEngine*>(fetchedEngine) != NULL );
NetworkEngine* network = static_cast<NetWorkEngine*>(fetchedEngine);
Only a object of type NetworkEngine should be putted on the "network" name, but maybe someone mistakenly put something else, the assert will make us safer without needing to worry about the overhead.

Function pointer to a non-static member function when the class type is unknown?

I'm working on a game project that features scratch-built controls rendered into an opengl context; things like buttons, scrollbars, listboxes, etc. Many of these controls are nested; for example, my listbox has a scrollbar, a scrollbar has 3 buttons, etc.
When a scrollbar changes value, I'd like it to call 'some' function (typically in it's parent object) that responds to the change. For example, if the listbox has a slider, it should instantiate the slider, then tell the new slider that it should call the listboxes 'onScroll(float)' function. All of the controls share a common base class, so I could have a 'base* parent' parent pointer, then do 'parent->onScroll(val)'. The problem though is what happens when the parent doesn't inheirit from base; there'd be no virtual onScroll() to follow through, so the top-level parent would have to periodically check to see if any of the child controls had changed value. This would also clutter up other controls, since they may not even have children, or may require different event types like when a list entry object is selected, etc.
A better solution would be to have the child object maintain a generic function pointer (like a callback), which can be set by the parent, and called by the child as necessary. Something like this:
typedef (*ptFuncF)(float);
class glBase {
public:
//position,isVisible,virtual mouseDown(x,y),etc
};
class glDerivedChild : public glBase {
public:
glDerivedChild();
~glDerivedChild();
void changeValue(float fIn) {
Value = fIn; //ignore these forward declaration errors
(*callBack)(fIn);
}
void setCallBack(ptFuncF pIn) {callBack = pIn;}
ptFuncF callBack;
float Value;
};
class glDerivedParent : public glBase {
public:
glDerivedParent() {
child = new glDerivedChild();
child->setCallBack(&onScroll);
}
~glDerivedParent() {delete child;}
void onScroll(float fIn) {
//do something
}
glDerivedChild* child;
};
class someFoo {
public:
someFoo() {
child->setCallBack(&setValue);
}
void setValue(float fIn) {
//do something else
}
glDerivedChild child;
};
I'm kinda new to function pointers, so I know I'm (obviously) doing many things wrong. I suspect it might involve something like "typedef (glBase::*ptFuncF)(float);" with the 'onScroll(f)' being an overridden virtual function, perhaps with a generic name like 'virtual void childCallBack(float)'. I'd prefer to keep the solution as close to vanilla as possible, so I want to avoid external libraries like boost. I've been scratching my head over this one for the better part of 8 hours, and I'm hoping someone can help. Thanks!
I think, what you want is some kind of events or signals mechanism.
You can study, how event processing is organized on Windows, for example. In short, your scrollbar generates new event in the system and then system propagates it to all elements, registered in the system.
More convenient mechanism is signal/slot mechanism. Boost or Qt provides such tools. I'll recomend this solution.
But if you still want to use just callbacks, I'll recommend using std::function (boost::function) (combined with std::bind (boost::bind), when required) instead of raw function pointers.
Use boost::function (or std::function if available). Like this (using your notation):
typedef std::function<void (float)> ptFuncF;
//...
void setCallBack(const ptFuncF &pIn);
//...
child->setCallBack(std::bind(&glDerivedParent::onScroll, this, _1));
//...
child->setCallBack(std::bind(&someFoo::setValue, this, _1));
A function pointer to a member function of a class has such a type:
<return type> (<class name>::*)(<arguments>)
For example:
typedef void (glBase::*ptFuncF)(float);
^^^^
by the way, you have forgot the `void` in your `typedef`
ptFuncF func = &glDerivedChild::onScroll;
And you use it like this:
glDerivedChild c;
(c.*func)(1.2);
In your particular example, the function is a member of the derived class itself, therefore you should call it like this:
(c.*c.callback)(1.2);
the inner c.callback is the function pointer. The rest is exactly as above, which is:
(class_instance.*function_pointer)(arguments);
You might want to take a look at this question also.
Ok, the workaround I came up with has some extra overhead and branching, but is otherwise reasonable.
Basically, each callback function is implemented as a virtual member function that recieves the needed parameters including a void* pointer to the object that made the call. Each derived object also has a base-class pointer that refers to the object that should recieve any events that it emits (typically its parent, but could be any object that inheirits from the base class). In case the control has multiple children, the callback function uses the void* pointer to distinguish between them. Here's an example:
class glBase {
public:
virtual onChildCallback(float fIn, void* caller);
glBase* parent;
};
class glSlider : public glBase {
public:
glSlider(glBase* parentIn);
void changeValue(float fIn) {
Value = fIn;
parent->onChildCallback(fIn, this);
}
float Value;
};
class glButton : public glBase {
public:
glButton(glBase* parentIn);
void onClick() {
parent->onChildCallback(0, this);
}
};
class glParent : public glBase {
public:
glParent(glBase* parentIn) : parent(parentIn) {
childA = new glSlider(this);
childB = new glButton(this);
}
void onChildCallback(float fIn, void* caller) {
if (caller == childA) {
//slider specific actions
} else if (caller == childB) {
//button specific actions
} else {
//generic actions
}
}
glSlider* childA;
glButton* childB;
};
Besides a reasonably small amount of overhead, the scheme is flexible enough that derived classes can ignore certain components or omit them altogether. I may go back to the function pointer idea later (thanks shahbaz), but half the infrastructure is the same for both schemes anyway and the extra overhead is minimal, especially since the number and variety of controls will be rather small. Having the callback function use a nested response is actually a little better since you don't need a separate function for each child object (eg onUpButton, onDownButton, etc).

Porting an existing class structure to smart pointers

I know this question is rather long, but I was not sure how to explain my problem in a shorter way. The question itself is about class hierarchy design and, especially, how to port an existing hierarchy based on pointers to one using smart pointers. If anyone can come up with some way to simplify my explanation and, thus, make this question more generic, please let me know. In that way, it might be useful for more SO readers.
I am designing a C++ application for handling a system that allows me to read some sensors. The system is composed of remotes machines from where I collect the measurements. This application must actually work with two different subsystems:
Aggregated system: this type of system contains several components from where I collect measurements. All the communication goes through the aggregated system which will redirect the data to the specific component if needed (global commands sent to the aggregated system itself do not need to be transferred to individual components).
Standalone system: in this case there is just a single system and all the communication (including global commands) is sent to that system.
Next you can see the class diagram I came up with:
The standalone system inherits both from ConnMgr and MeasurementDevice. On the other hand, an aggregated system splits its functionality between AggrSystem and Component.
Basically, as a user what I want to have is a MeasurementDevice object and transparently send data to corresponding endpoint, be it an aggregated system or a standalone one.
CURRENT IMPLEMENTATION
This is my current implementation. First, the two base abstract classes:
class MeasurementDevice {
public:
virtual ~MeasurementDevice() {}
virtual void send_data(const std::vector<char>& data) = 0;
};
class ConnMgr {
public:
ConnMgr(const std::string& addr) : addr_(addr) {}
virtual ~ConnMgr() {}
virtual void connect() = 0;
virtual void disconnect() = 0;
protected:
std::string addr_;
};
These are the classes for an aggregated system:
class Component : public MeasurementDevice {
public:
Component(AggrSystem& as, int slot) : aggr_sys_(as), slot_(slot) {}
void send_data(const std::vector<char>& data) {
aggr_sys_.send_data(slot_, data);
}
private:
AggrSystem& aggr_sys_;
int slot_;
};
class AggrSystem : public ConnMgr {
public:
AggrSystem(const std::string& addr) : ConnMgr(addr) {}
~AggrSystem() { for (auto& entry : components_) delete entry.second; }
// overridden virtual functions omitted (not using smart pointers)
MeasurementDevice* get_measurement_device(int slot) {
if (!is_slot_used(slot)) throw std::runtime_error("Empty slot");
return components_.find(slot)->second;
}
private:
std::map<int, Component*> components_;
bool is_slot_used(int slot) const {
return components_.find(slot) != components_.end();
}
void add_component(int slot) {
if (is_slot_used(slot)) throw std::runtime_error("Slot already used");
components_.insert(std::make_pair(slot, new Component(*this, slot)));
}
};
This is the code for a standalone system:
class StandAloneSystem : public ConnMgr, public MeasurementDevice {
public:
StandAloneSystem(const std::string& addr) : ConnMgr(addr) {}
// overridden virtual functions omitted (not using smart pointers)
MeasurementDevice* get_measurement_device() {
return this;
}
};
These are factory-like functions responsible for creating ConnMgr and MeasurementDevice objects:
typedef std::map<std::string, boost::any> Config;
ConnMgr* create_conn_mgr(const Config& cfg) {
const std::string& type =
boost::any_cast<std::string>(cfg.find("type")->second);
const std::string& addr =
boost::any_cast<std::string>(cfg.find("addr")->second);
ConnMgr* ep;
if (type == "aggregated") ep = new AggrSystem(addr);
else if (type == "standalone") ep = new StandAloneSystem(addr);
else throw std::runtime_error("Unknown type");
return ep;
}
MeasurementDevice* get_measurement_device(ConnMgr* ep, const Config& cfg) {
const std::string& type =
boost::any_cast<std::string>(cfg.find("type")->second);
if (type == "aggregated") {
int slot = boost::any_cast<int>(cfg.find("slot")->second);
AggrSystem* aggr_sys = dynamic_cast<AggrSystem*>(ep);
return aggr_sys->get_measurement_device(slot);
}
else if (type == "standalone") return dynamic_cast<StandAloneSystem*>(ep);
else throw std::runtime_error("Unknown type");
}
And finally here it is main(), showing a very simple usage case:
#define USE_AGGR
int main() {
Config config = {
{ "addr", boost::any(std::string("192.168.1.10")) },
#ifdef USE_AGGR
{ "type", boost::any(std::string("aggregated")) },
{ "slot", boost::any(1) },
#else
{ "type", boost::any(std::string("standalone")) },
#endif
};
ConnMgr* ep = create_conn_mgr(config);
ep->connect();
MeasurementDevice* dev = get_measurement_device(ep, config);
std::vector<char> data; // in real life data should contain something
dev->send_data(data);
ep->disconnect();
delete ep;
return 0;
}
PROPOSED CHANGES
First of all, I wonder whether there is a way to avoid the dynamic_cast in get_measurement_device. Since AggrSystem::get_measurement_device(int slot) and StandAloneSystem::get_measurement_device() have different signatures, it is not possible to create a common virtual method in the base class. I was thinking to add a common method accepting a map containing the options (e.g., the slot). In that case, I would not need to do the dynamic casting. Is this second approach preferable in terms of a cleaner design?
In order to port the class hierarchy to smart pointers I used unique_ptr. First I changed the map of components in AggrSystem to:
std::map<int, std::unique_ptr<Component> > components_;
The addition of a new Component now looks like:
void AggrSystem::add_component(int slot) {
if (is_slot_used(slot)) throw std::runtime_error("Slot already used");
components_.insert(std::make_pair(slot,
std::unique_ptr<Component>(new Component(*this, slot))));
}
For returning a Component I decided to return a raw pointer since the lifetime of a Component object is defined by the lifetime of an AggrSystem object:
MeasurementDevice* AggrSystem::get_measurement_device(int slot) {
if (!is_slot_used(slot)) throw std::runtime_error("Empty slot");
return components_.find(slot)->second.get();
}
Is returning a raw pointer a correct decision? If I use a shared_ptr, however, then I run into problems with the implementation for the standalone system:
MeasurementDevice* StandAloneSystem::get_measurement_device() {
return this;
}
In this case I cannot return a shared_ptr using this. I guess I could create one extra level of indirection and have something like StandAloneConnMgr and StandAloneMeasurementDevice, where the first class would hold a shared_ptr to an instance of the second.
So, overall, I wanted to ask whether this a good approach when using smart pointers. Would it be preferable to use a map of shared_ptr and return a shared_ptr too, or is it better the current approach based on using unique_ptr for ownership and raw pointer for accessing?
P.S: create_conn_mgr and main are changed as well so that instead of using a raw pointer (ConnMgr*) now I use unique_ptr<ConnMgr>. I did not add the code since the question was already long enough.
First of all, I wonder whether there is a way to avoid the
dynamic_cast in get_measurement_device.
I would attempt to unify the get_measurement_device signatures so that you can make this a virtual function in the base class.
So, overall, I wanted to ask whether this a good approach when using
smart pointers.
I think you've done a good job. You've basically converted your "single ownership" news and deletes to unique_ptr in a fairly mechanical fashion. This is exactly the right first (and perhaps last) step.
I also think you made the right decision in returning raw pointers from get_measurement_device because in your original code the clients of this function did not take ownership of this pointer. Dealing with raw pointers when you do not intend to share or transfer ownership is a good pattern that most programmers will recognize.
In summary, you've correctly translated your existing design to use smart pointers without changing the semantics of your design.
From here if you want to study the possibility of changing your design to one involving shared ownership, that is a perfectly valid next step. My own preference is to prefer unique ownership designs until a use case or circumstance demands shared ownership.
Unique ownership is not only more efficient, it is also easier to reason about. That ease in reasoning typically leads to fewer accidental cyclic memory ownership patters (cyclic memory ownership == leaked memory). Coders who just slap down shared_ptr every time they see a pointer are far more likely to end up with memory ownership cycles.
That being said, cyclic memory ownership is also possible using only unique_ptr. And if it happens, you need weak_ptr to break the cycle, and weak_ptr only works with shared_ptr. So the introduction of an ownership cycle is another good reason to migrate to shared_ptr.

Reconciling classes, inheritance, and C callbacks

In my C++ project, I've chosen to use a C library. In my zeal to have a well-abstracted and simple design, I've ended up doing a bit of a kludge. Part of my design requirement is that I can easily support multiple APIs and libraries for a given task (due, primarily, to my requirement for cross-platform support). So, I chose to create an abstract base class which would uniformly handle a given selection of libraries.
Consider this simplification of my design:
class BaseClass
{
public:
BaseClass() {}
~BaseClass() {}
bool init() { return doInit(); }
bool run() { return doWork(); }
void shutdown() { destroy(); }
private:
virtual bool doInit() = 0;
virtual bool doWork() = 0;
virtual void destroy() = 0;
};
And a class that inherits from it:
class LibrarySupportClass : public BaseClass
{
public:
LibrarySupportClass()
: BaseClass(), state_manager(new SomeOtherClass()) {}
int callbackA(int a, int b);
private:
virtual bool doInit();
virtual bool doWork();
virtual void destroy();
SomeOtherClass* state_manager;
};
// LSC.cpp:
bool LibrarySupportClass::doInit()
{
if (!libraryInit()) return false;
// the issue is that I can't do this:
libraryCallbackA(&LibrarySupportClass::callbackA);
return true;
}
// ... and so on
The problem I've run into is that because this is a C library, I'm required to provide a C-compatible callback of the form int (*)(int, int), but the library doesn't support an extra userdata pointer for these callbacks. I would prefer doing all of these callbacks within the class because the class carries a state object.
What I ended up doing is...
static LibrarySupportClass* _inst_ptr = NULL;
static int callbackADispatch(int a, int b)
{
_inst_ptr->callbackA(a, b);
}
bool LibrarySupportClass::doInit()
{
_inst_ptr = this;
if (!libraryInit()) return false;
// the issue is that I can't do this:
libraryCallbackA(&callbackADispatch);
return true;
}
This will clearly do Bad Things(TM) if LibrarySupportClass is instantiated more than once, so I considered using the singleton design, but for this one reason, I can't justify that choice.
Is there a better way?
You can justify that choice: your justification is that the C library only supports one callback instance.
Singletons scare me: It's not clear how to correctly destroy a singleton, and inheritance just complicates matters. I'll take another look at this approach.
Here's how I'd do it.
LibrarySupportClass.h
class LibrarySupportClass : public BaseClass
{
public:
LibrarySupportClass();
~LibrarySupportClass();
static int static_callbackA(int a, int b);
int callbackA(int a, int b);
private:
//copy and assignment are rivate and not implemented
LibrarySupportClass(const LibrarySupportClass&);
LibrarySupportClass& operator=(const LibrarySupportClass&);
private:
static LibrarySupportClass* singleton_instance;
};
LibrarySupportClass.cpp
LibrarySupportClass* LibrarySupportClass::singleton_instance = 0;
int LibrarySupportClass::static_callbackA(int a, int b)
{
if (!singleton_instance)
{
WHAT? unexpected callback while no instance exists
}
else
{
return singleton_instance->callback(a, b);
}
}
LibrarySupportClass::LibrarySupportClass()
{
if (singleton_instance)
{
WHAT? unexpected creation of a second concurrent instance
throw some kind of exception here
}
singleton_instance = this;
}
LibrarySupportClass::~LibrarySupportClass()
{
singleton_instance = 0;
}
My point is that you don't need to give it the external interface of a canonical 'singleton' (which e.g. makes it difficult to destroy).
Instead, the fact that there is only one of it can be a private implementation detail, and enforced by a private implementation detail (e.g. by the throw statement in the constructor) ... assuming that the application code is already such that it will not try to create more than one instance of this class.
Having an API like this (instead of the more canonical 'singleton' API) means that you can for example create an instance of this class on the stack if you want to (provided you don't try to create more than one of it).
The external constraint of the c library dictates that when your callback is called you don't have the identification of the "owning" instance of the callback. Therefore I think that your approach is correct.
I would suggest to declare the callbackDispatch method a static member of the class, and make the class itself a singleton (there are lots of examples of how to implement a singleton). This will let you implement similar classes for other libraries.
Dani beat me to the answer, but one other idea is that you could have a messaging system where the call back function dispatch the results to all or some of the instances of your class. If there isn't a clean way to figure out which instance is supposed to get the results, then just let the ones that don't need it ignore the results.
Of course this has the problem of performance if you have a lot of instances, and you have to iterate through the entire list.
The problem the way I see it is that because your method is not static, you can very easily end up having an internal state in a function that isn't supposed to have one, which, because there's a single instance on the top of the file, can be carried over between invocations, which is a -really- bad thing (tm). At the very least, as Dani suggested above, whatever methods you're calling from inside your C callback would have to be static so that you guarantee no residual state is left from an invocation of your callback.
The above assumes you have static LibrarySupportClass* _inst_ptr declared at the very top. As an alternative, consider having a factory function which will create working copies of your LibrarySupportClass on demand from a pool. These copies can then return to the pool after you're done with them and be recycled, so that you don't go around creating an instance every time you need that functionality.
This way you can have your objects keep state during a single callback invocation, since there's going to be a clear point where your instance is released and gets a green light to be reused. You will also be in a much better position for a multi-threaded environment, in which case each thread gets its own LibrarySupportClass instance.
The problem I've run into is that because this is a C library, I'm required to provide a C-compatible callback of the form int (*)(int, int), but the library doesn't support an extra userdata pointer for these callbacks
Can you elaborate? Is choosing a callback type based on userdata a problem?
Could your callback choose an instance based on a and/or b? If so, then register your library support classes in a global/static map and then have callbackADispatch() look up the correct instance in the map.
Serializing access to the map with a mutex would be a reasonable way to make this thread-safe, but beware: if the library holds any locks when it invokes your callback, then you may have to do something more clever to avoid deadlocks, depending on your lock hierarchy.