问题
Introduction
Peter Weinhart describes how to design a generic intrusive_ptr base class using CRTP, which may be used as follows:
class foo : intrusive_base<foo>
{
// foo-specific code.
};
This approach imposes the constraint that all foo
objects carry a reference counter. Assume that we keep foo
sometimes by value and only want to pay the price of the reference counter when we have a pointer. For example, sometimes we would like to create foo
instances and just move them around, and sometimes we want to allocate foo
on the heap.
Conceptually, the right mechanism for this scenario is a std::shared_ptr
. However, there are certain scenarios requiring raw pointers that would call for an intrusive pointer, e.g., when passing pointers through a C API that take void pointers. In this case, one would "ref" the pointer before passing it to the opaque API and "unref" when getting it back.
Having control over foo
, probably the best method would be to use a policy-based implementation and have a reference-counted and basic version of foo
. Without having control over foo
, an alternative design would to invert the inheritance relationship:
template <typename Base>
class intrusive : public Base
{
// ?
private:
std::atomic_size_t ref_count_;
};
typedef intrusive<foo> intrusive_foo;
// Assume boost::intrusive_ptr as intrusive pointer implementation
boost::intrusive_ptr<intrusive_foo> x = new intrusive_foo;
{
auto y = x; // Semantics: boost::intrusive_ptr_add_ref(x.get())
// At scope exit: boost::intrusive_ptr_release(x.get())
}
In the above mentioned article, Peter says that a such a "generic implementation of [intrusive
] would make use of C++0x variadic templates and perfect forwarding."
Question
How would the implementation of such a generic intrusive
class look like? I could see that it may benefit from C++11 inheriting constructors, but it is unclear to me how one would in fact implement the body of intrusive
using the mentioned tools.
回答1:
Using make_shared
gives you the same efficiency as an intrusive pointer.
In this case, one would "ref" the pointer before passing it to the opaque API and "unref" when getting it back.
As someone else said, you can use enable_shared_from_this
to get a shared_ptr
back from a raw pointer (as long as there is at least one shared_ptr
somewhere in the system which still owns the object)
But to answer the main question, I assume he means using variadic templates and perfect forwarding to define a constructor, which would look like:
template <typename Base>
class intrusive : public Base
{
template<typename... Args>
intrusive(Args&&... args)
: Base(std::forward<Args>(args)...), ref_count_(0)
{ }
This allow you to construct the intrusive
with any number of arguments of any type and they will be forwarded to the Base
, so you can construct it with any arguments that could be used to construct a Base
.
Another alternative would be to use C++11 inheriting constructors (which aren't implemented in any compiler AFAIK)
template <typename Base>
class intrusive : public Base
{
using Base::Base;
来源:https://stackoverflow.com/questions/9575647/reference-counting-with-a-generic-intrusive-pointer-client