New smart pointers for efficient refcounting
Hi everyone, In many places, to get memory management right, it is way more convenient and less error-prone to use a smart pointer, like SharedPtr (*). However, sometimes this leads to needless thrashing of the refcount. For example, any function that returns a newly created refcounted object should really give you a SharedPtr, to avoid leaking. But suppose that value is going to go directly into a data member that is a SharedPtr. That's going to lead to an extra ref and deref. In some spots that actually shows up on the profile. With manual refcounting you can special-case taking ownership of a newly created object, and avoid the extra ref and deref. I came up with a simple idea for how to deploy smart pointers throughout without suffering from this refcount thrash. It is inspired by the standard C++ library's auto_ptr. The basic idea is that you keep SharedPtr for most purposes; but in interfaces where you pass ownership, you use the new PassRefPtr. Passing ownership means either returning a newly allocated object (or otherwise one that the callee won't hold onto), or passing in as an argument an object the function is guaranteed to ref and hold onto. PassRefPtr works just like SharedPtr in most respects, except for assignment semantics: SharedPtr = SharedPtr // both keep a ref PassRefPtr = SharedPtr // both keep a ref SharedPtr = PassRefPtr // PassRefPtr transfers ownership and nils itself out PassRefPtr = PassRefPtr // second PassRefPtr transfers ownership and nils itself out Then you follow these rules: - local variables, global variables and data members should be a SharedPtr if they maintain a referece, or a raw pointer if they don't need to (for example a parent pointer, where the parent owns you) - function return values and parameters should be a raw pointer or a PassRefPtr (not a PassRefPtr& or const PassRefPtr&), depending on whether they transfer ownership - sometimes you might want to use a PassRefPtr for a local variable, if you plan to immediately transfer ownership Here's a test program I made that includes the PassRefPtr implementation and demonstrates use. A function getRefCounter returns a PassRefPtr which is then passed off to an Acceptor object's constructor. This runs in 2.95 seconds compared to 3.05 for this naiive SharedPtr version: So it's a measurable speedup to save those extra refs and derefs at construction time. I plan to integrate this soon. Any thoughts? Regards, Maciej * - I'd also like to rename SharedPtr to RefPtr and Shared to RefCounted, but I'm gonna stick with the SharedPtr terminology for this email.
On Nov 30, 2005, at 4:47 AM, Alexey Proskuryakov wrote:
On 30.11.2005 07:24, "Maciej Stachowiak" <mjs@apple.com> wrote:
I plan to integrate this soon. Any thoughts?
Does gcc support C++0x move semantics? With CodeWarrior, it gave me measurably better performance than PassRefPtr.
- WBR, Alexey Proskuryakov
<reftest3.cpp>
Nope, move semantics are not supported yet in gcc. This is my best shot at emulating something similar in a way that will work in older compilers. Eventually we will probably want to use move semantics but it may be a couple of years before C++0x is widely enough implemented. Cheers, Maciej
participants (2)
-
Alexey Proskuryakov
-
Maciej Stachowiak