How to mix shared pointers and references to C ++ objects

I have the following code that uses a C ++ object of the Datum class in the Objective-C work function:

 void work(const Datum &datum) { dispatch_async(dispatch_get_main_queue(), ^{ // Work with datum. }); } 

This code is called with the instance, which is actually boost::shared_ptr<Datum> , i.e.

 boost::shared_ptr<Datum> the_datum(new Datum()); work(*the_datum); 

In this situation, it is possible that the_datum instance will be freed before the block is started inside work (the dispatch_async call performs an asynchronous operation on the Datum , which is executed later, the call and, therefore, the work function returns immediately). This obviously leads to disaster.

One solution may be to not pass a link to work , but instead boost::shared_ptr<Datum> . But there may be situations where links are preferred; see, for example, this thread . Is there a way to keep the work interface (i.e. Pass Datum as a reference), but still prevent the release of the shared pointer until the block completes?

+6
source share
3 answers

It is not possible to accomplish this, leaving the work() interface the same, and pass the datum link. Cannot use datum to prevent link count from decreasing. Consider the following error:

 #include <memory> int main () { std::shared_ptr<int> p1(new int); int &x = *p1; std::shared_ptr<int> p2(&x); } 

This code crashes with double free, because the shared_ptr<> control structure does not match the object pointer, but is executed via shared_ptr<> .

What you can do is change work() to take shared_ptr() , but add another code to the block passed to dispatch_async() so that it can use the link inside this code. Since you are transferring ownership of the asynchronous procedure, unique_ptr<> should be used unique_ptr<> . I know zilch about Objective-C, so this syntax may be wrong:

 void work(std::unique_ptr<Datum> &datumptr_ref) { __block std::unique_ptr<Datum> datumptr(std::move(datumptr_ref)); dispatch_async(dispatch_get_main_queue(), ^{ Datum &datum = *datumptr // Work with datum. }); } 
+3
source

You must manage the links yourself:

 #include <iostream> #include <memory> extern "C" { typedef struct TagShared Shared; Shared* allocate(const std::shared_ptr<int>& ptr) { return (Shared*) new std::shared_ptr<int>(ptr); } void deallocate(Shared* shared) { delete (std::shared_ptr<int>*)shared; } } // extern "C" int main() { std::shared_ptr<int> s(new int(1)); Shared* p = allocate(s); // Inside Dispatch // No C++ but similar defined for TagShared std::cout << **(std::shared_ptr<int>*)p << std::endl; deallocate(p); return 0; } 
+1
source

You want to transfer ownership of std::unique_ptr something like this:

 void work(std::unique_ptr<Datum> datum) { dispatch_async(dispatch_get_main_queue(), ^{ // Work with datum. }); } std::unique_ptr<Datum> the_datum(new Datum()); work(std::move(the_datum)); 
0
source

Source: https://habr.com/ru/post/954081/


All Articles