I have a class:
class A
{
public:
A (A& in) {} // How to write a constructor from void* ?
int a;
int b;
const void* data() const { return static_cast<const void *>(this); }
};
I need to pass the class data thru a connection, which takes a void* buffer and "returns" also void*. An instance and some function:
A a;
void send(void* x);
void receive(void* x);
How can I type cast the a to send it as a parameter to foo()? The following code is not valid:
foo(static_cast<A&>(a));
How can I then, create a new object from a void* x pointer? What constructor and type cast to implement?
void* pA;
pA = ...
A a_copy {pA};
What would be the difference, if I have a struct not a class? I assume POD class here.
I would like not to use c-style casts, but rather C++ constructs.
How can I type cast the a to send it as a parameter to foo()? The following code is not valid:
foo(static_cast<A&>(a));
I assume you mean send() instead of foo()? If so, your code is not valid because you are casting it to a reference to A, when send() expects a pointer to void. So:
send(static_cast<void *>(&a));
Or, since you already have a member function that does the casting for you:
send(a.data());
How can I then, create a new object from a void* x pointer? What constructor and type cast to implement?
If you really want to do that, then again your constructor should take a pointer to void as argument, not a reference to another A:
class A
{
public:
A(void* in) {...}
...
};
You could then use std::memcpy() to copy all data into the class
A(void *in) {
std::memcpy(this, in, sizeof *this);
};
Of course, this should only be done if A is a POD type.
What would be the difference, if I have a struct not a class? I assume POD class here.
Nothing. A struct and a class are the same, the exception is just that struct defaults to making members public, and a class defaults to private.
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);
class Foo
{
public:
Foo(int& cnt) : cnt_(cnt) {}
void test() const
{
cnt_ = 0;
}
protected:
int& cnt_;
};
int cnt;
int main()
{
Foo foo(cnt);
foo.test();
}
The above code compiles. The test function is const, however we are allowed
to change the value of cnt_. If "cnt_" is not a reference then compiler
gives an error as expected. However if "cnt_" is a reference like above,
why doesn't compiler give an error ? We are still changing the state of the
object "Foo" inside a const member function, isn't it ?
The member cnt_, declared as:
int& cnt_;
is a reference, and inside the member function:
void test() const;
the const-qualification is applied to the members, i.e.: the reference, and not to the object referenced. Therefore, the object being referenced can still be modified through that reference, even inside a const member function, like the one above.
Note that, references can't be assigned after initialization anyway, so it really doesn't change what you can do with that reference.
Perhaps a pointer analogy will help.
Let's say you have:
struct Foo
{
Foo(int* cnt) : cnt_(cnt) {}
void test1() const
{
*cnt_ = 0;
}
void test2(int* p) const
{
cnt_ = p; // Not allowed
}
int* cnt_;
};
In test1, you are not changing cnt_. You are changing the value of cnt_ points to. That is allowed.
In test2, you are changing cnt_. That is not allowed.
In your case, you are not changing cnt_ to reference another object. You are changing the value of the object cnt_ references. Hence, it is allowed.
I am using a std::shared_ptr to point to a Node
template<typename T>
class A
{
class Node
{
T data;
std::shared_ptr<Node> link;
Node(T data, std::shared_ptr<Node> link);
};
void push(T data);
std::shared_ptr<Node> top;
};
template<typename T>
A<T>::Node::Node(T data, std::shared_ptr<typename A<T>::Node> link) :
data(data), link(link)
{
}
template<typename T>
void A<T>::push(T item)
{
if (top == nullptr)
{
top = std::make_shared<typename A<T>::Node>(new typename
A<T>::Node(item, nullptr));
}
else
{
top = std::make_shared<typename A<T>::Node>(new typename A<T>::Node(item, top));
}
}
The resulting declarations and definitions results in the compiler error
Severity Code Description Project File Line Suppression State
Error C2664 'Stack::Node::Node(const Stack::Node &)': cannot convert argument 1 from 'Stack::Node *' to 'const Stack::Node &' memory 901
What do I need to change to conform to <memory>?
A constructor of std::shared_ptr<T> accepts a pointer to T which you have created with new.
The function std::make_shared<T>(args...) does the new for you instead. The arguments you pass to make_shared will be passed on to the constructor of T. So you should almost never pass it a pointer created by new (unless you really want to new a T, and then pass that pointer as an argument to create another T!).
So for example, instead of:
std::make_shared<typename A<T>::Node>(
new typename A<T>::Node(item, top))
do just:
std::make_shared<typename A<T>::Node>(item, top)
(By the way, you don't actually need most of those typename A<T>:: qualifiers. Just plain Node is in scope whenever you're in the scope of A<T> or A<T>::Node, both in the class definitions and member definitions of that class after the member name. A<T>::Node without the typename would also work in those contexts because of the "member of the current instantiation" rule.)
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.
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.