Getting a boost::shared_ptr for this
You can derive from enable_shared_from_this and then you can use "shared_from_this()" instead of "this" to spawn a shared pointer to your own self object.
Example in the link:
#include <boost/enable_shared_from_this.hpp>
class Y: public boost::enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_from_this();
}
}
int main()
{
shared_ptr<Y> p(new Y);
shared_ptr<Y> q = p->f();
assert(p == q);
assert(!(p < q || q < p)); // p and q must share ownership
}
It's a good idea when spawning threads from a member function to boost::bind to a shared_from_this() instead of this. It will ensure that the object is not released.
std::shared_ptr of this
There is std::enable_shared_from_this
just for this purpose. You inherit from it and you can call .shared_from_this()
from inside the class. Also, you are creating circular dependencies here that can lead to resource leaks. That can be resolved with the use of std::weak_ptr
. So your code might look like this (assuming children rely on existence of parent and not the other way around):
class A;
class B;
class A
: public std::enable_shared_from_this<A>
{
public:
void addChild(std::shared_ptr<B> child)
{
children.push_back(child);
// like this
child->setParent(shared_from_this()); // ok
// ^^^^^^^^^^^^^^^^^^
}
private:
// note weak_ptr
std::list<std::weak_ptr<B>> children;
// ^^^^^^^^
};
class B
{
public:
void setParent(std::shared_ptr<A> parent)
{
this->parent = parent;
}
private:
std::shared_ptr<A> parent;
};
Note however, that calling .shared_from_this()
requires that this
is owned by std::shared_ptr
at the point of call. This means that you cannot create such object on stack anymore, and generally cannot call .shared_from_this()
from within a constructor or destructor.
Question on converting boost shared pointer to standard shared pointer
The shared pointer created has a destroy function object (deleter) that has state. In particular it has a copy of the boost shared ptr.
The destruction action does nothing, it is the destruction of deleter that cleans up the boost shared ptr.
There is a problem though:
Does the C++ standard fully specify cleanup of the deleter itself? E.g. it might stay around when only weak references remain?
The standard does guarantee a minimum lifetime for the deleter, leaving the possibility that lives longer than that.
Destroying the destruction object is not specified to occur in either the constructor of std::shared_ptr
nor the destructor of std::shared_ptr
. It would be reasonable to destroy it either after it is called, or when the reference counting block is destroyed - in the second case, we end up with it lasting until the last weak ptr goes away.
From the draft standard:
[Note: It is unspecified whether the pointer remains valid longer than that. This can happen if the implementation doesn’t destroy the deleter until all
weak_ptr
instances that share ownership with p have been destroyed. — end note]
The possibility to defer destruction of the deleter is clear. So in that case we end up with shared_ptr
s that doesn't destruct their element instance when we want it to be called depending on unspecified details of the C++ implementation you run it on. That is a bad idea.
Better Alternative
I would personally go with a similar trick based on the aliasing constructor instead. It is just as simple, has no additional overhead, and the semantics are actually correct:
template<class T>
std::shared_ptr<T>
as_std_shared_ptr(boost::shared_ptr<T> bp)
{
if (!bp) return nullptr;
// a std shared pointer to boost shared ptr. Yes.
auto pq = std::make_shared<boost::shared_ptr<T>>(std::move(bp));
// aliasing ctor. Hide the double shared ptr. Sneaky.
return std::shared_ptr<T>(pq, pq.get()->get());
}
This is much less of a hack than the code from the question, because lifetime
of the boost shared ptr is no longer tied to the (unspecified) lifetime of the deleter instance.
boost::shared_ptr from pointer
If you have a shared_ptr managing a pointer and then create another shared_ptr managing the same pointer (NOT copying the original shared_ptr), you end up with two managers for the same resource. When one of the two reach a reference count of 0, it will delete the object and the other shared_ptr will point to deleted memory with all that follows.
Get point-to type of boost shared_ptr
Documentation says there's a member typedef called element_type
:
This example program runs fine (assertion passes):
#include <boost/shared_ptr.hpp>
#include <boost/type_traits.hpp>
#include <cassert>
int main()
{
bool b = boost::is_same<boost::shared_ptr<int>::element_type, int>::value;
assert(b);
}
Given the typedef you've already declared, you can use it like this:
typedef queue_ptr::element_type elem_type;
v.push_back( boost::make_shared<elem_type>( /* args for ctor */ ) );
Using boost::function with a parameter to shared pointer to derived class
There's no co-variance for function prototypes. Different signatures are simply that: different types.
In this case you'd need to wrap the function with a converting wrapper.
Let's create a few facility definitions:
using result_t = int;
struct A { };
struct B : A { };
typedef boost::shared_ptr<A> APtr;
typedef boost::shared_ptr<B> BPtr;
result_t f1(APtr) { return 1; }
result_t f2(BPtr) { return 2; }
typedef boost::function <result_t(APtr const&)> funOfA;
typedef boost::function <result_t(BPtr const&)> funOfB;
Now wrapping funOfB
as a funOfA
would look like this:
funOfA wrapFunOfB(const funOfB f) {
struct {
funOfB _f;
result_t operator()(APtr const& a) const {
return _f(boost::static_pointer_cast<B>(a));
}
} wrap { f };
return wrap;
}
Now you can easily write:
int main() {
F(f1);
F(wrapFunOfB(f2));
}
Simple C++03 Demo
Live On Coliru
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <iostream>
typedef int result_t;
struct A { int i; };
struct B : A { int j; };
typedef boost::shared_ptr<A> APtr;
typedef boost::shared_ptr<B> BPtr;
result_t f1(APtr) { return 1; }
result_t f2(BPtr) { return 2; }
typedef boost::function <result_t(APtr const&)> funOfA;
typedef boost::function <result_t(BPtr const&)> funOfB;
struct Wrapper {
typedef result_t result_type;
funOfB _f;
result_t operator()(APtr const& a) {
return _f(boost::static_pointer_cast<B>(a));
}
};
funOfA wrapFunOfB(const funOfB f) {
Wrapper wrap = { f };
return wrap;
}
void F(const funOfA f) {
APtr a = boost::make_shared<A>();
APtr b = boost::make_shared<B>();
//std::cout << "f(a): " << f(a) << "\n"; // UNDEFINED BEHAVIOUR if f wraps a funOfB
std::cout << "f(b): " << f(b) << "\n";
}
int main() {
F(f1);
F(wrapFunOfB(f2));
}
Prints
f(b): 1
f(b): 2
PROBLEMS, WARNINGS: dynamic_pointer_cast<>
If F
actually invokes the parameter on an object that isn't actually of type B
, that static_cast<>
will invoke Undefined Behaviour.
If you want to protect against that, use dynamic_pointer_cast
, which requires the classes A
and B
to be polymorphic types.
Live On Coliru
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <iostream>
typedef int result_t;
struct A { int i; virtual ~A() {} };
struct B : A { int j; };
typedef boost::shared_ptr<A> APtr;
typedef boost::shared_ptr<B> BPtr;
result_t f1(APtr a) { return a?1 : 0; }
result_t f2(BPtr b) { return b?2 : -99; }
typedef boost::function <result_t(APtr const&)> funOfA;
typedef boost::function <result_t(BPtr const&)> funOfB;
struct Wrapper {
typedef result_t result_type;
funOfB _f;
result_t operator()(APtr const& a) {
return _f(boost::dynamic_pointer_cast<B>(a));
}
};
funOfA wrapFunOfB(const funOfB f) {
Wrapper wrap = { f };
return wrap;
}
void F(const funOfA f) {
APtr a = boost::make_shared<A>();
APtr b = boost::make_shared<B>();
std::cout << "f(a): " << f(a) << "\n";
std::cout << "f(b): " << f(b) << "\n";
}
int main() {
F(f1);
F(wrapFunOfB(f2));
}
Prints
f(a): 1
f(b): 1
f(a): -99
f(b): 2
C++11 Version
Things get a little more elegant here. Notably, the Wrapper class can be local, and anonymous:
funOfA wrapFunOfB(const funOfB f) {
struct {
typedef result_t result_type;
funOfB _f;
result_t operator()(APtr const& a) {
return _f(std::dynamic_pointer_cast<B>(a));
}
} wrap { f };
return wrap;
}
Next level: use a lambda instead:
funOfA wrapFunOfB(const funOfB f) {
return [f](APtr const& a) { return f(std::dynamic_pointer_cast<B>(a)); };
}
Live On Coliru
#include <memory>
#include <functional>
#include <iostream>
typedef int result_t;
struct A { int i; virtual ~A() {} };
struct B : A { int j; };
typedef std::shared_ptr<A> APtr;
typedef std::shared_ptr<B> BPtr;
result_t f1(APtr a) { return a?1 : 0; }
result_t f2(BPtr b) { return b?2 : -99; }
typedef std::function<result_t(APtr const&)> funOfA;
typedef std::function<result_t(BPtr const&)> funOfB;
funOfA wrapFunOfB(const funOfB f) {
return [f](APtr const& a) { return f(std::dynamic_pointer_cast<B>(a)); };
}
void F(const funOfA f) {
APtr a = std::make_shared<A>();
APtr b = std::make_shared<B>();
std::cout << "f(a): " << f(a) << "\n";
std::cout << "f(b): " << f(b) << "\n";
}
int main() {
F(f1);
F(wrapFunOfB(f2));
}
That's 25% code reduction.
Cohabitation of boost::shared_ptr and std::shared_ptr
You could do it like this:
template<typename T>
boost::shared_ptr<T> make_shared_ptr(std::shared_ptr<T>& ptr)
{
return boost::shared_ptr<T>(ptr.get(), [ptr](T*) mutable {ptr.reset();});
}
template<typename T>
std::shared_ptr<T> make_shared_ptr(boost::shared_ptr<T>& ptr)
{
return std::shared_ptr<T>(ptr.get(), [ptr](T*) mutable {ptr.reset();});
}
EDIT: Note that this does not work with weak references to the source ptr. So be careful with those!
Should I switch from using boost::shared_ptr to std::shared_ptr?
There are a couple of reasons to switch over to std::shared_ptr
:
- You remove a dependency on Boost.
- Debuggers. Depending on your compiler and debugger, the debugger may be "smart" about
std::shared_ptr
and show the pointed to object directly, where it wouldn't for say, boost's implementation. At least in Visual Studio,std::shared_ptr
looks like a plain pointer in the debugger, whileboost::shared_ptr
exposes a bunch of boost's innards. - Other new features defined in your linked question.
You get an implementation which is almost guaranteed to be move-semantics enabled, which might save a few refcount modifications. (Theoretically -- I've not tested this myself)As of 2014-07-22 at least,boost::shared_ptr
understands move semantics.(Actually I stand corrected. See this -- the specialization for this is forstd::shared_ptr
correctly usesdelete []
on array types, whileboost::shared_ptr
causes undefined behavior in such cases (you must useshared_array
or a custom deleter)unique_ptr
only, notshared_ptr
.)
And one major glaring reason not to:
- You'd be limiting yourself to C++11 compiler and standard library implementations.
Finally, you don't really have to choose. (And if you're targeting a specific compiler series (e.g. MSVC and GCC), you could easily extend this to use std::tr1::shared_ptr
when available. Unfortunately there doesn't seem to be a standard way to detect TR1 support)
#if __cplusplus > 199711L
#include <memory>
namespace MyProject
{
using std::shared_ptr;
}
#else
#include <boost/shared_ptr.hpp>
namespace MyProject
{
using boost::shared_ptr;
}
#endif
Related Topics
Optimize Template Replacement of a Switch
Specializing a Template on a Lambda in C++0X
How to Use Memcpy in C++ to Copy Classes That Have No Pointers or Virtual Functions
Forward Declaration VS Include
Default Visibility of C++ Class/Struct Members
Forcing Nvidia Gpu Programmatically in Optimus Laptops
Localtime VS Localtime_S and Appropriate Input Arguments
Calling Constructor of a Class Member in Constructor
Interpolate from One Color to Another
How Much Overhead Is There in Calling a Function in C++
Type Erasure in C++: How Boost::Shared_Ptr and Boost::Function Work
How Much Overhead Is There When Creating a Thread