Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manually incrementing and decrementing a boost::shared_ptr?

Is there a way to manually increment and decrement the count of a shared_ptr in C++?

The problem that I am trying to solve is as follows. I am writing a library in C++ but the interface has to be in pure C. Internally, I would like to use shared_ptr to simplify memory management while preserving the ability to pass a raw pointer through the C interface.

When I pass a raw pointer through the interface, I would like to increment the reference count. The client will then be responsible to call a function that will decrement the reference count when it no longer needs the passed object.

like image 811
D R Avatar asked Sep 27 '09 04:09

D R


3 Answers

Maybe you are using boost::shared_ptr accross DLL boundaries, what won't work properly. In this case boost::intrusive_ptr might help you out. This is a common case of misuse of shared_ptr people try to work around with dirty hacks... Maybe I am wrong in your case but there should be no good reason to do what you try to do ;-)

ADDED 07/2010: The issues seem to come more from DLL loading/unloading than from the shared_ptr itself. Even the boost rationale doesn't tell much about the cases when boost::intrusive_ptr should be preferred over shared_ptr. I switched to .NET development and didn't follow the details of TR1 regarding this topic, so beware this answer might not be valid anymore now...

like image 86
jdehaan Avatar answered Nov 05 '22 06:11

jdehaan


In your suggestion

The client will then be responsible to decrement the counter.

means that the client in question is responsible for memory management, and that your trust her. I still do not understand why.

It is not possible to actually modify the shared_ptr counter... (hum, I'll explain at the end how to...) but there are other solutions.

Solution 1: complete ownership to the client

Hand over the pointer to the client (shared_ptr::release) and expect it to pass the ownership back to you when calling back (or simply deleting the object if it is not really shared).

That's actually the traditional approach when dealing with raw pointers and it apply here as well. The downside is that you actually release ownership for this shared_ptr only. If the object is actually shared that might prove inconvenient... so bear with me.

Solution 2: with a callback

This solution means that you always keep ownership and are responsible to maintain this object alive (and kicking) for as long as the client needs it. When the client is done with the object, you expect her to tell you so and invoke a callback in your code that will perform the necessary cleanup.

struct Object;

class Pool // may be a singleton, may be synchronized for multi-thread usage
{
public:
  int accept(boost::shared_ptr<Object>); // adds ptr to the map, returns NEW id
  void release(int id) { m_objects.erase(id); }

private:
  std::map< int, boost::shared_ptr<Object> > m_objects;
}; // class Pool

This way, your client 'decrementing' the counter is actually your client calling a callback method with the id you used, and you deleting one shared_ptr :)

Hacking boost::shared_ptr

As I said it is possible (since we are in C++) to actually hack into the shared_ptr. There are even several ways to do it.

The best way (and easiest) is simply to copy the file down under another name (my_shared_ptr ?) and then:

  • change the include guards
  • include the real shared_ptr at the beginning
  • rename any instance of shared_ptr with your own name (and change the private to public to access the attributes)
  • remove all the stuff that is already defined in the real file to avoid clashes

This way you easily obtain a shared_ptr of your own, for which you can access the count. It does not solve the problem of having the C code directly accessing the counter though, you may have to 'simplify' the code here to replace it by a built-in (which works if you are not multi-threaded, and is downright disastrous if you are).

I purposely left out the 'reinterpret_cast' trick and the pointer offsets ones. There are just so many ways to gain illegit access to something in C/C++!

May I advise you NOT to use the hacks though? The two solutions I presented above should be enough to tackle your problem.

like image 21
Matthieu M. Avatar answered Nov 05 '22 07:11

Matthieu M.


You should do separation of concerns here: if the client passes in a raw pointer, the client will be responsible for memory management (i.e. clean up afterwards). If you create the pointers, you will be responsible for memory management. This will also help you with the DLL boundary issues that were mentioned in another answer.

like image 22
MP24 Avatar answered Nov 05 '22 07:11

MP24