?
dlopen/dlclose unterhalten selbst einen Referenzzähler auf Bibliotheken, die Handle-Map sollte also nicht notwendig sein.
Ich finge das etwa so an:
#include <functional>
#include <iostream>
#include <stdexcept>
#include <string>
#include <dlfcn.h>
#include <unistd.h>
struct link_error : public std::invalid_argument {
link_error() : std::invalid_argument(dlerror()) { }
};
class dll_handle {
public:
dll_handle(std::string const &dll_name)
: name_ (dll_name),
handle_(0) { }
dll_handle(dll_handle const &rhs)
: name_(rhs.name_),
handle_(0) {
if(rhs.handle_) {
open();
}
}
~dll_handle() {
try {
close();
} catch(link_error const &e) {
std::cerr << e.what() << std::endl;
}
}
void open() {
if(!handle_) {
handle_ = dlopen(name_.c_str(), RTLD_LAZY);
if(!handle_) {
throw link_error();
}
}
}
void close() {
if(handle_ && dlclose(handle_) != 0) {
throw link_error();
}
}
void *symbol(std::string const &symbol_name) {
open();
void *sym = dlsym(handle_, symbol_name.c_str());
if(!sym) {
throw link_error();
}
return sym;
}
private:
std::string name_;
void *handle_;
};
template<typename T> class weak_function;
template<typename R, typename... A> class weak_function<R(A...)> {
public:
weak_function(std::string const &dll, std::string const &symbol)
: dll_ (dll),
symbol_name_(symbol),
fo_ () { }
void link_symbol() {
if(!fo_) {
R (*sym)(A...);
*reinterpret_cast<void**>(&sym) = dll_.symbol(symbol_name_);
fo_ = sym;
}
}
R operator()(A... a) {
link_symbol();
return fo_.operator()(a...);
}
private:
dll_handle dll_;
std::string symbol_name_;
std::function<R(A...)> fo_;
};
int main() {
weak_function<pid_t(void)> wf("/lib/libc.so.6", "getpid");
weak_function<pid_t(void)> wf2("/lib/libc.so.6", "foobarbazqux");
std::cout << wf() << std::endl;
std::cout << getpid() << std::endl;
wf2();
}
Allerdings ist das eine ziemlich grobe Angelegenheit. Ein großes Designproblem ist 1. Kopiersemantik und 2. const-correctness. Wenn ich etwa eine Funktion der Form
void call(weak_function<void()> const &func) { func(); }
habe, wie soll sich func verhalten, wenn die Funktion noch nicht geladen ist? Wahrscheinlich könnte man die Brechstangenmethode (mutable) in diesem Fall sogar ganz gut vertreten, allerdings kommt das auf die weiteren Umstände an.