4 ms·
There's no requirement or even expectation that your snippet of code in principle works (even after working out the issues in the snippet you posted, such as ne
by Kranar 5y ago
There's no requirement or even expectation that your snippet of code in principle works (even after working out the issues in the snippet you posted, such as needing to use the .* operator, the fact that member functions are not the same size as void*, and other quirky details).
The only way something somewhat similar to what you posted could possibly work would be to have some_local_list allocated/constructed dynamically from the same shared object that contains the the member function and to expose the member function using extern "C".
For example something like:
auto some_local_list = create_list(...);
list_size(some_local_list);
Where create_list is a function loaded from the same dlopen and returns a dynamically allocated and opaque handle to a list, and list_size is also a function loaded from dlopen that is exported using extern "C".
With this approach it's certainly possible for a compiler to optimize out unused member variables. Any other approach is undefined behavior and may or may not work.
- jcelerier 5y ago> There's no requirement or even expectation that your snippet of code in principle works "in principle" goes away as soon as we use dlopen, as it implies a lot of things on the way C++ will be supported on that given platform ; no one cares about C++ in a vacuum. In practice, different .dll / .so / .dylib communicate through C++ APIs all the time ; all relevant platforms have to support that at some level (which can sometimes cause strong headaches, for sure: https://www.codesynthesis.com/~boris/blog/2010/01/18/dll-export-cxx-templates/ https://www.codesynthesis.com/~boris/blog/2010/01/18/dll-exp... ).
- Kranar 5y agoWhen I say in principle, I don't mean according to a strict interpretation of the standard in a vacuum. I mean that even if I were to extend to you a great deal of liberties and operate at the level of what you're attempting to accomplish, your approach is fundamentally invalid and results in buggy code that will break and is entirely unneccessary. The way you accomplish dynamically loading member functions is by exporting a plain C function using extern "C" that takes an opaque handle to the object you wish to operate on, and whose implementation wraps the member function whose operation you wish to expose. Pointers to member functions are fundamentally not compatible with void* and hence may not reliably be returned using dlsym. Only once the member function is bound to an object (using the .* operator, ie. object.*member) is the resulting pointer compatible with a void* (in C++11 it's implementation defined). Until then, they not only have different sizes, their size may even be different within different translation units of the same application! In practice you are right that DLLs and shared objects communicate through C++ APIs all the time, and the reliable way that they do so is by using extern "C". The article you linked to is exactly the kind of pain, undefined behavior, and buggy problems you will encounter when you try to use any other mechanism than the plain and straight forward mechanism that exists precisely for the purpose of facilitating this kind of communication. The reason my point is worth making, as opposed to just being a pedantic technicality, is because this approach is precisely what allows compilers to make various optimizations that continue to work safely even in situations where objects, functions, and member functions are used across dynamic boundaries. If you don't follow this approach, then the compiler will make certain optimizations that will result in disastrous behavior. If you don't want to take my word for it, hopefully you'll take the advice of the ISO CPP [1]: "do not attempt to “cast” a pointer-to-member-function into a pointer-to-function; the result is undefined and probably disastrous. E.g., a pointer-to-member-function is not required to contain the machine address of the appropriate function." [1] https://isocpp.org/wiki/faq/pointers-to-members#addr-of-memfn https://isocpp.org/wiki/faq/pointers-to-members#addr-of-memf...
- tcbawo 5y agoI have seen implementations of type erasure/delegates that store an instance pointer and pointer-to-member-function as an instance and pointer-to-member-function of a dummy type with the same calling convention. It's interesting how many different member function pointer sizes Windows has. Undefined behavior and compiler dependent, but consistent.
- pjmlp 5y agoOr COM like APIs.