RFC - lifetime management

View: New views
7 Messages — Rating Filter:   Alert me  

RFC - lifetime management

by Johan Torp :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I'd love to get some feedback on a tiny utility I've been thinking about.

I oftenly create small objects which I just want to keep alive as long
as some other object exists. It is often RAII objects, but many other
types of small classes fall into this category.

A simple "user heap" could take ownership of such instances and delay
deletion until itself is deleted. The basic interface of - let's call
it heap - would look like this:

  template<class T> T& heap::put(T*);

Example usage:

     boost::shared_ptr<SomeView> view;
     // Keep controller alive while view exits
     view->get_heap().put(new SomeController(*view));


For classes with loads of RAII object members, usage could look like this:

  class Foo {
    Foo()  {
      keep_alive_.put(new RAIIBar(...));
      keep_alive_.put(new RAIIWhatever(...));
    }
  private:
    heap keep_alive_;
  };


Support should be added for putting shared_ptrs and auto_ptrs. I have
a wide variety of naming suggestions and an extended interface for
premature deletion but I'll save those for a later post.


What do you think? Please give me your thoughts.

Johan
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: RFC - lifetime management

by Simon Richter-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

Johan Torp schrieb:

> A simple "user heap" could take ownership of such instances and delay
> deletion until itself is deleted. The basic interface of - let's call
> it heap - would look like this:

That would be very similar to a ptr_* container that assumes ownership
of the object, with a common base class for all the objects to
facilitate destruction.

    Simon
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: RFC - lifetime management

by Johan Torp :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Simon Richter-2 wrote:
That would be very similar to a ptr_* container that assumes ownership
of the object, with a common base class for all the objects to
facilitate destruction.
Glad to get some response :)

Requiring a common base class/interface is a huge demand. This would couple client code a lot for the sake of such a small utility and it wouldn't be directly compatible with already existing classes.

The proposed "heap" has very different semantics compared to a container. Once you put something in the heap you never want to access it again. All you want to achieve is delayed and synchronized destruction.

You can achieve similar functionality using a std::vector<boost::any> in which you insert boost::shared_ptrs. The syntax is a lot worse though and more importantly, more difficult to understand.

Compare:

  std::vector<boost::any> keep_alive;
  // Always use named smart ptrs
  boost::shared_ptr<boost::signals::scoped_connection>
    connection(new boost::signals::scoped_connection(signal, slot));
  keep_alive.push_back(connection);

  boost::heap keep_alive;
  keep_alive.put(new boost::signals::scoped_connection(signal, slot));

In the latter case we clearly signal something - we're not interested in the connection variable, only it's lifetime.


Johan

Re: RFC - lifetime management

by Martin Schulz-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


> For classes with loads of RAII object members, usage could
> look like this:
>
>   class Foo {
>     Foo()  {
>       keep_alive_.put(new RAIIBar(...));
>       keep_alive_.put(new RAIIWhatever(...));
>     }
>   private:
>     heap keep_alive_;
>   };

To me, that sounds very much like a std::vector<boost:shared_ptr<void>
>:

  typedef std::vector<boost::shared_ptr<void> > heap;

  class Foo {
    Foo()  {
      keep_alive_.push_back(boost::shared_ptr<RAIIBar>(new
RAIIBar(...)));
      keep_alive_.push_back(boost::shared_ptr<RAIIWhatever>(new
RAIIWhatever(...)));
    }
  private:
    heap keep_alive_;
  };

Does this do what you intended?

With a bit of syntactic sugar, it would be possible to avoid the
intermediate shared_ptr type, probably. I consider all real work already
done.

> Support should be added for putting shared_ptrs and
> auto_ptrs.

You get this for free with the above.

> I have a wide variety of naming suggestions and an
> extended interface for premature deletion but I'll save those
> for a later post.

keep_alive_.erase(keep_alive_.begin()+n);

Should do that. Again, some syntactic sugar might help.



Is that what you thought about?

Yours,
        Martin.

--
Dr. Martin Schulz (schulz@...)
Software Engineer
Synopsys GmbH
Karl-Hammerschmidt-Str. 34
D-85609 Dornach, Germany
Munich office: +49 (89) 993-20203
Home office:   +49 (721) 6099511
http://www.synopsys.com
 
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: RFC - lifetime management

by Johan Torp :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Martin Schulz-3 wrote:
To me, that sounds very much like a std::vector<boost:shared_ptr<void>
[snip]
Does this do what you intended?

With a bit of syntactic sugar, it would be possible to avoid the
intermediate shared_ptr type, probably. I consider all real work already
done.

Is that what you thought about?
Yes that's basically it! I often create std::vector<boost::any> containing boost:shared_ptrs. Using std::vector<boost::shared_ptr<void> > is clearer and lessens the need for this utility class a bit.

Still, the heap class is even more clear, easier to use and easier to reason about.
I see the following benefits over std::vector<boost::shared_ptr<void> >:

  1. More informative class and method names

  2. You can't access anything put in the heap through the heap. This makes code analysis a lot easier.
      For instance, using heap.put(new Foo) you are sure noone can access the Foo instance at all.

  3. There is no way to delete something in a heap or clear it so you are sure what's put will remain alive
      as long as the heap. (I no longer believe premature deletion is good idea).
      Heaps should be non-copyable, vectors aren't.

  4. Because of 2 & 3 suitable classes (such as display list nodes) can expose a get_heap-method
      without risking the class's clients affecting each other or the instance.

  5. Raw pointers can be handled more efficiently than shared_ptrs

  6. Better syntax. Repeating a long type name twice as with boost shared_ptr can be tedious

Still I'm not sure if these points are enough to motivate a new utility class. It's not exactly a killer app, even though I find it very useful in MVC architectures (linking controllers life time to views) and classes with lots of RAII members. What do you think?

Thanks for your input! /Johan




Re: RFC - lifetime management

by Martin Schulz-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> Still, the heap class is even more clear, easier to use and
> easier to reason about.
> I see the following benefits over
> std::vector<boost::shared_ptr<void> >:
>
>   1. More informative class and method names

Well, the name heap makes me think of a certain kind of memory
management system. Probably a name like Keepalive_bucket would
be clearer?

>       Heaps should be non-copyable, vectors aren't.

Ok, that is a design choice and clearly influences the semantic.

>   5. Raw pointers can be handled more efficiently than shared_ptrs

But think of it - if that pointed-to object is in use by some other
means,
it would be destroyed by the heap destructor nevertheless. Using shared
pointers, the pointed-to objects are kept alive as long as either the
heap
lives or as long they are used, whatever is longer.

>   6. Better syntax. Repeating a long type name twice as with
> boost shared_ptr can be tedious

Yes, I already noted that.

> Still I'm not sure if these points are enough to motivate a
> new utility class. It's not exactly a killer app, even though
> I find it very useful in MVC architectures (linking
> controllers life time to views) and classes with lots of RAII
> members. What do you think?

If ist helpfull to you, then go ahead and use & improve it.


An (untested) wrapper class I would start with would be something like:

class Keepalive: private boost::noncopyable {
        Std::vector< boost::shared_ptr<void> > v;
public:
        template <typename T> void put(boost::shared_ptr<T> p) {
v.push_back(p); };
        template <typename T> void put(std::auto_ptr<T>& p) {
v.push_back(boost::shared_ptr<T>(p)); };
        template <typename T> void put(T *p) {
v.push_back(boost::shared_ptr<T>(p)); };
};

Does that solve your needs?

--
Dr. Martin Schulz (schulz@...)
Software Engineer
Synopsys GmbH
Karl-Hammerschmidt-Str. 34
D-85609 Dornach, Germany
Munich office: +49 (89) 993-20203
Home office:   +49 (721) 6099511
http://www.synopsys.com
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: RFC - lifetime management

by Johan Torp :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

>>   1. More informative class and method names
>
>Well, the name heap makes me think of a certain kind of memory
>management system. Probably a name like Keepalive_bucket would
>be clearer?

Yes! There are probably even better names. Names might involve manual/garbage collection, owner, life time [synchronizer], delayed/synchronized destruction/or, respirator, reaper, .. well, probably getting a bit too creative here :)  I'd love more suggestions/opinions though!


>>   5. Raw pointers can be handled more efficiently than shared_ptrs
>
>But think of it - if that pointed-to object is in use by some other
>means, it would be destroyed by the heap destructor nevertheless.

Creating a shared_ptr from a raw pointer has the same "problem". If users fail to realize this, they've misunderstood the whole point of the class.


>An (untested) wrapper class I would start with would be something like:
>
>class Keepalive: private boost::noncopyable {
> Std::vector< boost::shared_ptr<void> > v;
>public:
> template <typename T> void put(boost::shared_ptr<T> p) {
>v.push_back(p); };
> template <typename T> void put(std::auto_ptr<T>& p) {
>v.push_back(boost::shared_ptr<T>(p)); };
> template <typename T> void put(T *p) {
>v.push_back(boost::shared_ptr<T>(p)); };
>};
>
>Does that solve your needs?

Yes, this is basically what the implementation I'm using today I looks like. The question is if anybody else finds it useful.

Again - thanks for your input!

Johan