dlopen() is a C function used for dynamically loading shared libraries at runtime. The pattern, in case you're not familiar, is thus:
Call dlopen("libpath", flag) to get a void *handle to the library
Call dlsym(handle, "object_name") to get a void *object to the thing you want from the library
Do what you want with object
Call dlclose (handle) to unload the library.
This is, in C++, a perfect use-case for the so-called aliasing constructor of std::shared_ptr. The pattern becomes:
Construct a std::shared_ptr<void> handle from dlopen("libpath", flag) that will call dlclose() when its destructor is called
Construct a std::shared_ptr<void> object from handle and dlsym(handle, "object_name")
Now we can pass object wherever we want, and completely forget about handle; when object's destructor is called, whenever that happens to be, dlclose() will be called automagically
Brilliant pattern, and it works beautifully. One small problem, though. The pattern above requires a cast from void* to whatever_type_object_is*. If "object_name" refers to a function (which most of the time it does, considering the use-case), this is undefined behavior.
In C, there is a hack to get around this. From the dlopen man page:
// ...
void *handle;
double (*cosine)(double);
// ...
handle = dlopen("libm.so", RTLD_LAZY);
// ...
/* Writing: cosine = double (*)(double)) dlsym(handle, "cos");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&cosine) = dlsym(handle, "cos");
// ...
which obviously works just fine, in C. But is there an easy way to do this with std::shared_ptr?
The pattern above requires a cast from void* to whatever_type_object_is*. If "object_name" refers to a function (which most of the time it does, considering the use-case), this is undefined behavior.
Well this is not entirely true, at least in C++ it is just conditionally-supported.
5.2.10.8 says:
Converting a function pointer to an object pointer type or vice versa is conditionally-supported. The meaning
of such a conversion is implementation-defined, except that if an implementation supports conversions in
both directions, converting a prvalue of one type to the other type and back, possibly with different cvqualification,
shall yield the original pointer value.
So assuming that what dlsym does internally is casting a function pointer to a void*, I believe that you are ok if you just cast it back to a function pointer.
Something like this?
struct dlib
{
public:
template<class T>
std::shared_ptr<T> sym(const char* name) const {
if (!handle) return {};
void* sym = dlsym(handle->get(), name);
if (!sym) return {};
return {reinterpret_cast<T*>(sym), handle};
}
// returns a smart pointer pointing at a function for name:
template<class Sig>
std::shared_ptr<Sig*> pfunc(const char* name) const {
if (!handle) return {};
void* sym = dlsym(handle->get(), name);
if (!sym) return {};
Sig* ret = 0;
// apparently approved hack to convert void* to function pointer
// in some silly compilers:
*reinterpret_cast<void**>(&ret) = sym;
return {ret, handle};
}
// returns a std::function<Sig> for a name:
template<class Sig>
std::function<Sig> function(const char* name) const {
// shared pointer to a function pointer:
auto pf = pfunc(name);
if (!pf) return {};
return [pf=std::move(pf)](auto&&...args)->decltype(auto){
return (*pf)(decltype(args)(args)...);
};
}
dlib() = default;
dlib(dlib const&)=default;
dlib(dlib &&)=default;
dlib& operator=(dlib const&)=default;
dlib& operator=(dlib &&)=default;
dlib(const char* name, int flag) {
void* h = dlopen(name, flag);
if (h)
{
// set handle to cleanup the dlopen:
handle=std::shared_ptr<void>(
h,
[](void* handle){
int r = dlclose(handle);
ASSERT(r==0);
}
);
}
}
explicit operator bool() const { return (bool)handle; }
private:
std::shared_ptr<void> handle;
};
I doubt that hack is needed. As #sbabbi noted, the round-trip to void* is conditionally supported. On a system using dlsym to return function pointers, it better be supported.
You can make a struct to have your pointer to function and handle to library:
template<typename T>
struct dlsymbol {
dlsymbol( const std::string &name, std::shared_ptr<void> handle ) :
m_handle( std::move( handle ) )
{
*(void **)(&m_func) = dlsym( handle.get(), name.c_str );
}
std::shared_ptr<void> m_handle;
T *m_func;
};
auto cosine = std::make_shared<dlsymbol<double(double)>>( "cos", handle );
auto d = cosine->m_func( 1.0 );
I did not compile it, but I think it is sufficient to show the idea.
Related
Question: I have a template function that takes an object pointer of the template param class, and a method pointer to a method of that class. I can then call that method on that object immediately. But I don't want to call it immediately. Instead, I want to save both pointers for future use, and call them at a later time in code that won't be contextually aware of what that type is.
In legacy C/C++99 code, we pass in a function pointer and a void* user data pointer to code that will do a callback (e.g., on a timer finishing, a user event, etc.) We'd almost invariably pass in an object pointer as the user-data, and write a one-line C function that casts the user data pointer to that type and called a method on the object:
void TimerCB( void* pvUserData, void* pvCallerData ) {
( (Foo*) pvUserData )->TimerDone( pvCallerData );
}
In C++11, std::function lets us pass in lambdas and std::bind, or a C function without a user data.
However, in practice, nearly every time I simply want to have a method on the current object called. I can do that with a lambda or bind but it's verbose:
class Timer {
:
virtual void SubscribeTimer( const char* pszTime,
std::function<void(Data*)> pfn );
};
void Timer::SubscribeTimer( const char* pszTime,
std::function<void(Data*)> pfn ) {
cout << " calling std::function\n";
Data d;
pfn( &d );
}
// Inside methods of class Foo:
SubscribeTimer( "14:59:50", std::bind( &Foo::TimerDone, this, std::placeholders::_1 ) );
SubscribeTimer( "14:59:50", [this](Data* pdata){this->TimerDone( pdata );} );
I'm able to pass in method pointers, if I know the class of their object at compile time, like this:
class Timer {
:
virtual void SubscribeTimer( const char* pszTime,
void (Foo::*pfn)( Data* pd ), Foo* pfoo );
};
void Timer::SubscribeTimer( const char* pszTime, void (Foo::*pfn)( Data* pd ), Foo* pfoo ) {
cout << " calling method\n";
Data d;
(pfoo->*pfn)( &d );
}
// Inside methods of class Foo:
SubscribeTimer( "14:59:50", &Foo::TimerDone, this );
However, this is not acceptable, because my Timer class is of the utility library level of the project, and shouldn't need to be made aware of every possible user class like Foo.
OK, so it turns out I can templatize that method so I no longer need to know what the type of object that Foo is or that the method is a method of. This compiles without error. (Method and class pointer swapped so it's clear which overloaded function is called.)
class Timer {
:
template<typename T> void SubscribeTimer( const char* pszTime, T* pthis,
void (T::*pfn)( Data* pd ) );
};
template<typename T> void Foo::SubscribeTimer( const char* pszTime, T* pthis,
void (T::*pmethod)( Data* pd ) ) {
cout << " calling any method\n";
Data d;
(pthis->*pmethod)( &d ); // <-- PROBLEMATIC LINE
}
// Inside methods of class Foo:
SubscribeTimer( "14:59:50", this, &Foo::TimerDone );
So... Victory! That's the simpler syntax I wanted instead of the messier lambda and std::bind shown above.
BUT HERE IS MY QUESTION. The above example works because the line labeled PROBLEMATIC LINE is in a context where the compiler knows the type of pthis. But in practice, SubscribeTimer() doesn't call that callback right away. Instead, it saves that value for future reference. Long in the future, if the app is still running at 14:59:50, that callback will be called.
You already know about all the pieces of the answer (std::function, lambdas); you just need to put them together.
std::function<void(Data*)> f = [=](Data* d) { (pthis->*pmethod)(d); }
Now save this function, e.g. in a data member. When it comes time to call it, that's just
Data d;
f_member(&d);
#include <iostream>
#include <set>
using namespace std;
class StudentT {
public:
int id;
string name;
public:
StudentT(int _id, string _name) : id(_id), name(_name) {
}
int getId() {
return id;
}
string getName() {
return name;
}
};
inline bool operator< (StudentT s1, StudentT s2) {
return s1.getId() < s2.getId();
}
int main() {
set<StudentT> st;
StudentT s1(0, "Tom");
StudentT s2(1, "Tim");
st.insert(s1);
st.insert(s2);
set<StudentT> :: iterator itr;
for (itr = st.begin(); itr != st.end(); itr++) {
cout << itr->getId() << " " << itr->getName() << endl;
}
return 0;
}
In line:
cout << itr->getId() << " " << itr->getName() << endl;
It give an error that:
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'int StudentT::getId()' discards qualifiers
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'std::string StudentT::getName()' discards qualifiers
What's wrong with this code? Thank you!
The objects in the std::set are stored as const StudentT. So when you try to call getId() with the const object the compiler detects a problem, mainly you're calling a non-const member function on const object which is not allowed because non-const member functions make NO PROMISE not to modify the object; so the compiler is going to make a safe assumption that getId() might attempt to modify the object but at the same time, it also notices that the object is const; so any attempt to modify the const object should be an error. Hence compiler generates an error message.
The solution is simple: make the functions const as:
int getId() const {
return id;
}
string getName() const {
return name;
}
This is necessary because now you can call getId() and getName() on const objects as:
void f(const StudentT & s)
{
cout << s.getId(); //now okay, but error with your versions
cout << s.getName(); //now okay, but error with your versions
}
As a sidenote, you should implement operator< as :
inline bool operator< (const StudentT & s1, const StudentT & s2)
{
return s1.getId() < s2.getId();
}
Note parameters are now const reference.
Member functions that do not modify the class instance should be declared as const:
int getId() const {
return id;
}
string getName() const {
return name;
}
Anytime you see "discards qualifiers", it's talking about const or volatile.
Actually the C++ standard (i.e. C++ 0x draft) says (tnx to #Xeo & #Ben Voigt for pointing that out to me):
23.2.4 Associative containers
5 For set and multiset the value type
is the same as the key type. For map
and multimap it is equal to pair. Keys in an associative
container are immutable.
6 iterator of
an associative container is of the
bidirectional iterator category. For
associative containers where the value
type is the same as the key type, both
iterator and const_iterator are
constant iterators. It is unspecified
whether or not iterator and
const_iterator are the same type.
So VC++ 2008 Dinkumware implementation is faulty.
Old answer:
You got that error because in certain implementations of the std lib the set::iterator is the same as set::const_iterator.
For example libstdc++ (shipped with g++) has it (see here for the entire source code):
typedef typename _Rep_type::const_iterator iterator;
typedef typename _Rep_type::const_iterator const_iterator;
And in SGI's docs it states:
iterator Container Iterator used to iterate through a set.
const_iterator Container Const iterator used to iterate through a set. (Iterator and const_iterator are the same type.)
On the other hand VC++ 2008 Express compiles your code without complaining that you're calling non const methods on set::iterators.
Let's me give a more detail example. As to the below struct:
struct Count{
uint32_t c;
Count(uint32_t i=0):c(i){}
uint32_t getCount(){
return c;
}
uint32_t add(const Count& count){
uint32_t total = c + count.getCount();
return total;
}
};
As you see the above, the IDE(CLion), will give tips Non-const function 'getCount' is called on the const object. In the method add count is declared as const object, but the method getCount is not const method, so count.getCount() may change the members in count.
Compile error as below(core message in my compiler):
error: passing 'const xy_stl::Count' as 'this' argument discards qualifiers [-fpermissive]
To solve the above problem, you can:
change the method uint32_t getCount(){...} to uint32_t getCount() const {...}. So count.getCount() won't change the members in count.
or
change uint32_t add(const Count& count){...} to uint32_t add(Count& count){...}. So count don't care about changing members in it.
As to your problem, objects in the std::set are stored as const StudentT, but the method getId and getName are not const, so you give the above error.
You can also see this question Meaning of 'const' last in a function declaration of a class? for more detail.
Imagine a typical realization of the PIMPL idiom:
class ObjectImpl;
class Object
{
Object(ObjectImpl* object_impl)
: _impl(object_impl);
private:
ObjectImpl* _impl;
};
What I'm looking for is a way to reuse the same implementation to wrap a type T that's either ObjectImpl or const ObjectImpl but nothing else:
class ObjectImpl;
class Object
{
Object(T* object_impl)
: _impl(object_impl);
private:
// T being either ObjectImpl or const ObjectImpl
T* _impl;
};
What I'm trying to achieve is retaining logical constness through the PIMPL interface so that I'm disallowed by the compiler to call non-const methods on an Object wrapping a const ObjectImpl*.
It's basically just this trick borrowed from one of Scott Meyers Effective C++ books but with an added layer of abstraction:
struct SData
{
const Data* data() const { return _data; }
Data* data() { return _data; }
private:
Data* _data:
};
Of course I could copy the entire class into a class ConstObject and have it wrap a const* Object instead of an Object* but I'm obviously trying to prevent code duplication.
I've also thought about templates but they seem a bit overkill for the task at hand. For one, I want T to only be either ObjectImpl or const ObjectImpl. Secondly, templates seem to work against the idea of PIMPL when exported as a DLL interface. Is there a better solution to go with?
CRTP.
template<class Storage>
struct const_Object_helper {
Storage* self() { return static_cast<D*>(this); }
Storage const* self() const { return static_cast<D*>(this); }
// const access code goes here, get it via `self()->PImpl()`
};
struct const_Object: const_Object_helper<const_Object> {
const_Object( objectImpl const* impl ):pImpl(impl) {}
private:
objectImpl const* pImpl = nullptr;
objectImpl const* PImpl() const { return pImpl; }
template<class Storage>
friend struct const_Object_helper;
};
struct Object: const_Object_helper<Object> {
// put non-const object code here
Object( objectImpl* impl ):pImpl(impl) {}
operator const_Object() const {
return {PImpl()}; // note, a copy/clone/rc increase may be needed here
}
private:
objectImpl* pImpl = nullptr;
objectImpl const* PImpl() const { return pImpl; }
objectImpl* PImpl() { return pImpl; }
template<class Storage>
friend struct const_Object_helper;
};
This is the zero runtime overhead version, but requires the implementation of const_Object_helper and Object_helper to be exposed. As it just involves forwarding stuff to the actual impl, this seems relatively harmless.
You can remove that need by replacing the CRTP part of the helpers with a pure-virtual objectImpl const* get_pimpl() const = 0 and objectImpl* get_pimpl() = 0, then implement them in the derived types.
Another, somewhat crazy, approach would be to use an any augmented with type-erased operations (you also want to teach the type erasure mechanism about const, and that a super_any with fewer interfaces can be implicitly converted over without doing another layer of wrapping).
Here we define certain operations, say print and dance and boogie:
auto const print = make_any_method<void(std::ostream&), true>(
[](auto&&self, std::ostream& s) {
s << decltype(self)(self);
}
);
auto const dance = make_any_method<void()>(
[](auto&&self) {
decltype(self)(self).dance();
}
);
auto const dance = make_any_method<double(), true>(
[](auto&&self) {
return decltype(self)(self).boogie();
}
);
Now we create two types:
using object = super_any< decltype(print), decltype(dance), decltype(boogie) > object;
using const_object = super_any< decltype(print), decltype(boogie) >;
Next, augment the super_any with the ability to assign-from sources with strictly weaker requirements.
Our object o; can (o->*dance)(). Our const_object co; can double d = (co->*boogie)();.
Anything can be stored in an object that supports the operations described by print, boogie and dance, plus the requirements of any (copy, destroy, assign). Anything at all.
Similarly, the const_object supports anything that can be described by print and boogie and copy/destroy/assign.
Derived types from object or const_object can add operator overloading features easily.
This technique is advanced. You can use boost::type_erasure to do it, probably slicker than this sketch.
I would suggest the following general design pattern. It wastes an additional pointer, but will enforce the requirement that the const object will be able to only access const methods of the private object:
class ObjectImpl;
class const_Object {
public:
const_Object(const ObjectImpl* object_impl)
: _impl(object_impl);
// Only const methods
private:
const ObjectImpl* _impl;
};
class Object : public const_Object
{
Object(ObjectImpl* object_impl)
: const_Object(object_impl), _impl(object_impl);
// non-const methods go here.
private:
ObjectImpl* _impl;
};
Suppose there is a class with a few data members, such as this:
struct s {
char c;
int i;
};
If I need a const-pointer to a member, it's simple enough:
auto s::* const ptr = &s::c;
If I try to create a static member of the same type, some weird things start happening...
For instance, this segfaulted the compiler (gcc 4.9.3):
struct s {
char c;
int i;
static auto s::* const static_ptr = &s::c;
};
// internal compiler error: Segmentation fault
// static auto s::* const static_ptr = &s::c;
// ^
Using it as a static member of a different class at least finishes compiling:
struct t {
static auto s::* const static_ptr = &s::c;
};
// error: 'constexpr' needed for in-class initialization of static data member 'char s::* const t::static_ptr' of non-integral type [-fpermissive]
// static auto s::* const static_ptr = &s::c;
// ^
That last error I don't understand, isn't &s::c a constexpr?
I do have a way to make it work, eg:
// also works with `struct s` this way, `struct t` is not needed for this
struct t {
static char s::* const static_ptr;
};
char s::* const t::static_ptr = &s::c;
But for several reasons this is undesirable:
auto cannot be used except in the definition, if it is initialized outside the class then the type must be declared.
Declaring the type explicitly means either repeating the type or repeating the member name (as decltype(s::c)) - more places to maintain the same name = more mistakes possible.
The above is even more of a nuisance with specialized class templates, where for each specialization this would need to be done inside and outside the class.
From this I have a two part question.
1. Why isn't &s::c a constexpr? Is there a way to make it one?
2. Is there a way to specify a static member that is a fixed pointer to a member of another class, with the type automatically determined, without resorting to decltype?
I have tried this as a member of struct s and get the same error (constexpr needed):
static constexpr auto s::* const member_c () {
return &s::c;
}
So I'm at a loss as to what the compiler's issue is with this sort of syntax, it just doesn't make sense to me why a reference to a data member (not an instance member reference) is not a constant at compile time.
Say I have a struct (in real life, that's an automaton):
struct automaton
{
bool get_final() const { return final; }
void set_final() { final = true; }
bool final = false;
};
for which I want to provide a view that sees it transposed (iow, reversed, or mirrored). Because I have more than just a single automaton class, I have a class template that wraps my automaton (I really want composition, not inheritance), and bounces all the function calls to the wrapped automaton, reversing what needs to be. For sake of simplicity, here, it just forwards the calls.
By hand, I'd get
template <typename Aut>
struct transposed_by_hand
{
Aut& aut;
auto get_final() const -> bool
{
return aut.get_final();
}
auto set_final() -> void
{
aut.set_final();
}
};
But there are many functions, and I don't want to hard-code so much information (the function signature) in the wrapper. Thanks to variadic templates and perfect forwarding for the incoming arguments, and decltype for the result, it's quite easy to have one macro to factor the definition of all the const member-functions, and another macro for non-const member functions (the difference being precisely the const). Basically, in this case it boils down to this:
template <typename Aut>
struct transposed_with_decltype
{
Aut& aut;
auto get_final() const -> decltype(aut.get_final())
{
return aut.get_final();
}
auto set_final() -> decltype(aut.set_final())
{
aut.set_final();
}
};
This works well for non-const automata, but breaks if I wrap a const automaton:
int main()
{
const automaton aut;
transposed_by_hand<const automaton> trh = { aut };
transposed_with_decltype<const automaton> trd = { aut };
}
My compilers complain that (G++ 4.9):
f.cc: In instantiation of 'struct transposed_with_decltype<const automaton>':
f.cc:44:49: required from here
f.cc:34:12: error: passing 'const automaton' as 'this' argument of 'void automaton::set_final()' discards qualifiers [-fpermissive]
auto set_final() -> decltype(aut.set_final())
^
and (Clang++ 3.3):
f.cc:42:23: error: default initialization of an object of const type 'const automaton' requires a user-provided default constructor
const automaton aut;
^
f.cc:34:36: error: member function 'set_final' not viable: 'this' argument has type 'const automaton', but function is not marked const
auto set_final() -> decltype(aut.set_final())
^~~
f.cc:44:49: note: in instantiation of template class 'transposed_with_decltype<const automaton>' requested here
transposed_with_decltype<const automaton> trd = { aut };
^
f.cc:6:12: note: 'set_final' declared here
void set_final() { final = true; }
^
2 errors generated.
And they are right! The expression in the decltype is breaking the const-ness of the wrapped automaton. Yet, I am not going to use this function, I swear. Just like I will not use the corresponding one wrapped by hand.
So my question is: is there a means to write the definition of the wrapping set_final so that I don't have to spell out its signature (input and output)? I have tried to use std::enable_if, but it changes nothing to the problem here. And anyway, it would need that the compiler be lazy, and accepts not to evaluate the second parameter of std::enable_if if it does not need to...
template <typename Aut>
struct transposed_with_decltype
{
Aut& aut;
auto get_final() const -> decltype(aut.get_final())
{
return aut.get_final();
}
auto set_final() -> typename std::enable_if<!std::is_const<Aut>::value,
decltype(aut.set_final())>::type
{
aut.set_final();
}
};
Thanks in advance.
I can get it to work (using GCC 4.6) just by using the advice Xeo mentions in his comment. That is, I turn the function into a trivial template, like so:
template<typename = void>
auto set_final() -> decltype(aut.set_final()) {
return aut.set_final();
}
== EDIT ==
Luc Danton comments below that a more recent GCC may reject the code, complaining that the decltype isn't dependent. I only have 4.6 here, but perhaps this could be worked around using something like this:
template<typename KLUDGE = int>
auto set_final() -> decltype((&aut+KLUDGE(0))->set_final()) {
return aut.set_final();
}
YMMV.