C++11: Replace All Non-Owning Raw Pointers with Std::Shared_Ptr()

C++11: Replace all non-owning raw pointers with std::shared_ptr()?

Personally, this is how I (more or less) do it:

  • unique_ptrs are for sole ownership
  • raw pointers mean whoever gave me the raw pointer guarantees the lifetime of that object to match or exceed my lifetime.
  • shared_ptrs are for shared ownership
  • weak_ptrs are for when a system wants to check if the object still exists before using it. This is rare in my code since I find it cleaner to have a system guarantee the lifetime of anything it passes it's subsystems (in which case I use a raw pointer)

By far I use more unique_ptrs than shared_ptrs, and more raw pointers than weak pointers.

To avoid creation of std::shared_ptr from raw pointers?

Although this might not be the best way to do that, one way to do get your constructor protected to a certain degree but still make it callable by std::make_shared is the following:

class MyClass
{
protected:
struct ConstructorGuard {};

public:
MyClass(ConstructorGuard g) {}

static std::shared_ptr<MyClass> create()
{
return std::make_shared<MyClass>(ConstructorGuard());
}
};

The constructor itself is public, but it cannot be called from outside the class, because it requires an argument of type ConstructorGuard which is a protected nested class, such that only the class itself (and the derived classes) can construct such an object to pass it to the constructor.

C++: Replace raw pointers with shared and weak ptr

You can use shared_ptr for m_childs and weak_ptr for m_parent.

However, it might be still reasonable to retain the raw pointer to the parent Node and don't use any weak pointers at all. The safeguarding mechanism behind this is the invariant that non-null parent always exists.

Another option is using shared_ptr in ChainDescriptor only and retaining all raw pointers in Node. This approach avoids weak pointers and has a clean ownership policy (parent nodes own their children).

Weak pointers will help you to manage the memory automatically, but the backside of this are fuzzy ownership logic and performance penalties.

Replacing raw pointers in vectors with std::shared_ptr

You say, that the object container would be the "owner" of the objects in question. In that case, that you have a clear owning relationship, using std::shared_ptr is not ideal. Rather, stick with what you have.

However, if you cannot guarantee, that a pointer has been removed from multiple_selection and/or simple_selection before it is deleted, you have to act. One possible action could be, that you use shared_ptr. In that case, an object could still continue to exist in one of the selections, even, if it is removed (via shared_ptr::reset or just assigning a null value) from object_container.

The other alternative is to make sure, that objects get removed thoroughly: If something is to be deleted, remove ALL references to it from the selections and from the object_container, and THEN delete it. If you strictly follow this scheme, you don't need the overhead of shared_ptr.

Dependency injection in C++11 without raw pointers

If I wanted to do this, the first thing I'd do is kill your interface, and instead use this:

SomeAlgorithm(std::function<double(Point,Point)> distanceCalculator_)

type erased invocation object.

I could do a drop-in replacement using your EuclideanDistanceCalculator like this:

std::function<double(Point,Point)> UseEuclidean() {
auto obj = std::make_shared<EuclideanDistance>();
return [obj](Point a, Point b)->double {
return obj->distance( a, b );
};
}
SomeAlgorithm foo( UseEuclidean() );

but as distance calculators rarely require state, we could do away with the object.

With C++1y support, this shortens to:

std::function<double(Point,Point>> UseEuclidean() {
return [obj = std::make_shared<EuclideanDistance>()](Point a, Point b)->double {
return obj->distance( a, b );
};
}

which as it no longer requires a local variable, can be used inline:

SomeAlgorithm foo( [obj = std::make_shared<EuclideanDistance>()](Point a, Point b)->double {
return obj->distance( a, b );
} );

but again, the EuclideanDistance doesn't have any real state, so instead we can just

std::function<double(Point,Point>> EuclideanDistance() {
return [](Point a, Point b)->double {
return sqrt( (b.x-a.x)*(b.x-a.x) + (b.y-a.y)*(b.y*a.y) );
};
}

If we really don't need movement but we do need state, we can write a unique_function< R(Args...) > type that does not support non-move based assignment, and store one of those instead.

The core of this is that the interface DistanceCalculator is noise. The name of the variable is usually enough. std::function< double(Point,Point) > m_DistanceCalculator is clear in what it does. The creator of the type-erasure object std::function handles any lifetime management issues, we just store the function object by value.

If your actual dependency injection is more complicated (say multiple different related callbacks), using an interface isn't bad. If you want to avoid copy requirements, I'd go with this:

struct InterfaceForDependencyStuff {
virtual void method1() = 0;
virtual void method2() = 0;
virtual int method3( double, char ) = 0;
virtual ~InterfaceForDependencyStuff() {}; // optional if you want to do more work later, but probably worth it
};

then, write up your own make_unique<T>(Args&&...) (a std one is coming in C++1y), and use it like this:

Interface:

SomeAlgorithm(std::unique_ptr<InterfaceForDependencyStuff> pDependencyStuff)

Use:

SomeAlgorithm foo(std::make_unique<ImplementationForDependencyStuff>( blah blah blah ));

If you don't want virtual ~InterfaceForDependencyStuff() and want to use unique_ptr, you have to use a unique_ptr that stores its deleter (by passing in a stateful deleter).

On the other hand, if std::shared_ptr already comes with a make_shared, and it stores its deleter statefully by default. So if you go with shared_ptr storage of your interface, you get:

SomeAlgorithm(std::shared_ptr<InterfaceForDependencyStuff> pDependencyStuff)

and

SomeAlgorithm foo(std::make_shared<ImplementationForDependencyStuff>( blah blah blah ));

and make_shared will store a pointer-to-function that deletes ImplementationForDependencyStuff that will not be lost when you convert it to a std::shared_ptr<InterfaceForDependencyStuff>, so you can safely lack a virtual destructor in InterfaceForDependencyStuff. I personally would not bother, and leave virtual ~InterfaceForDependencyStuff there.

C++11 storing multiple shared pointers as raw pointers

The reason you'll use a shared_ptr is that you want the memory it points to to be freed when all instances that point to it go out of scope. The shared_ptr is destroyed right after you call .get() on it, so you immediately have a dangling pointer. The result of the dereference operation is undefined, which means that it may or may not return a value that makes sense, or it could even do something completely unrelated (like crashing).

This is a feature. You want this to happen: otherwise, you'd be leaking memory. Imagine this code:

vector<int> integers;
integers.push_back(*make_shared<int>(6).get());

If the memory wasn't freed, there would be no way to release it afterwards, because there's no way you could recover the shared_ptr's managed pointer.



Related Topics



Leave a reply



Submit