-
Notifications
You must be signed in to change notification settings - Fork 761
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue with shared_from_this after utilizing load_and_allocate #47
Comments
Is it possible to make a version of this without the extract stuff? Also I'm not incredibly familiar with the mechanics of |
Here's a way better example, apologies, the previous example was just me sketching on an existing test I was working on (and also missed saving handles, but that wasn't the issue):
enable_shared_from_this is a class you can derive your own classes from. When you do, enable_shared_from_this has an internal weak_ptr reference to "this", and you can access shared_from_this() which returns a locked copy of that weak_ptr. The issue is that when you perform your allocation within load_and_allocate, the weak_ptr ref never gets any love, and so it sits stagnant and if you try to call shared_from_this() you get a crash when it tries to lock the janky weak_ptr ref it should have stored. |
http://gcc.gnu.org/onlinedocs/gcc-4.6.4/libstdc++/api/a01043_source.html search for class enable_shared_from_this for an example implementation. |
You are right - the way this works is that the constructor for For load_and_allocate, we initialize the shared_ptr with aligned_storage of the appropriate size, which is then cast to the true type being loaded. So I'm guessing that shared_ptr is still trying to assign something to this weak_ptr, even though it's just junk. When we give this back to the user using The only way for that weak_ptr to be properly initialized is through the constructor of shared_ptr. Might be tricky to fix this without getting too hacky. |
nods I was thinking the same. I rely on enable_shared_from_this and I would totally appreciate effort in fixing it. But I don't think it'll be easy to do without somehow breaking encapsulation in a hacky way. I just hope it can be done without resorting to std implementation specific work-arounds. |
OK I have an extremely hacky solution for this working that should (I think?) work independently from implementation. The gist is this:
Thoughts on this monstrosity? |
Unfortunately I do not have very much experience using aligned_storage or placement new. The steps you outline seem to be reasonable, however. I don't know of a better way certainly. As long as the weak_ptr is pointing to the final object (the same one as the owning shared_ptr) that seems fine. |
Fixes #47 When we detect a shared_ptr being loaded in load_and_allocate that also is of a type that derives from enable_shared_from_this, extra work is done to save the state of the enable_shared_from_this before the user gets to meddle with it via placement new inside of cereal::allocate. State is restored after getting back from the user.
Oh no! We have a problem, capn' Polymorphic stuff is busted. This was one of the things I was a bit worried about, but didn't know if it would be an issue or not.
|
You are right, there is still an issue with polymorphic types. cereal loads the true type for your polymorphic type (let's say the class hierarchy is This can be fixed but there will be some limitations on the hierarchies supported by cereal. For a polymorphic type, stored in a shared_ptr, deriving from enable_shared_from_this, and finally using load_and_allocate: either the current pointer type or its true pointer type (polymorphism) must be the class that derived from enable_shared_from_this. In addition the way I'm going to implement this it will attempt to cast to the most base class, so having both the parent and derived class inherit from enable_share_from_this will not be supported. |
Also unrelated to this issue, there is no need to register the base class of a polymorphic hierarchy (e.g. Node in your example). |
Might not be fixed as soon as I thought - it's pretty tricky to do. Unfortunately the standard doesn't define an implementation for the internals of enable_shared_from_this, so I hesitate to implement a solution that relies on any one implementation (although clang, gcc, and msvc all use a weak_ptr internally). If you want to locally fix this for yourself in the meantime, you can do something like this: template <class T>
struct Dummy
{
std::weak_ptr<T> weak;
};
int main()
{
// loading up some stuff
std::shared_ptr<MyClass> bla;
ar( bla );
reinterpret_cast<Dummy<MyClass> *>( static_cast<std::enable_shared_from_this<MyClass> *>( bla.get() ) )->weak = bla;
} This should work over any of the compilers I mentioned and properly set up the internal weak_ptr. |
Thanks dude. Awesome response! |
Functionality to figure out the type enable_shared_from_this was templated on for any base type of the current type. see #47
Should be completely good to go, and done in a non hacky way! Test this on VS for us, we haven't had the chance yet. |
This stumped me for some time. I was looking for errors in my own code for quite some time before I created the following example. enable_shared_from_this doesn't seem to get its weak_ptr reconstituted properly on load.
The text was updated successfully, but these errors were encountered: