c++ Garbage collection and calling destructors - c++

Per-frame I need to allocate some data that needs to stick around until the end of the frame.
Currently, I'm allocating the data off a different memory pool that allows me to mark it with the frame count. At the end of the frame, I walk the memory pool and delete the memory that was allocated in a particular frame.
The problem I'm running into is that in order to keep a hold on the data, I have to place it in a structure thusly:
struct FrameMemory
{
uint32 frameIndex;
bool allocatedType; //0 = new(), 1 = new[]
void* pMemPtr;
}
So later, when i get around to freeing the memory, it looks something like this:
{
for(all blocks)
if(block[i].frameIndex == targetIndex)
if(block[i].allocatedType == 0)
delete block[i].pMemPtr;
else if (block[i].allocatedType ==1)
delete[] block[i].pMemPtr;
}
The issue is that, because I have to overload the pointer to the memory as a void*, the DELETE operator doesn't properly DELETE the memory as its' native base type. IE the destructor NEVER gets called for the object.
I've attempted to find ways to use smart-pointer templated objects for the solution, but in order to do that, I have to overload the templated class to a non-templated base-type, which makes deletion even more difficult.
Does anyone have a solution to a problem like this?

If you don't want to force all the objects to inherit from Destructible, you can store a pointer to a deleter function (or functor) along with the pointer to the data itself. The client code is responsible for providing a function that knows how to delete the data correctly, typically something like:
void xxx_deleter(void *data) {
xxx *ptr = static_cast<xxx *>(data);
delete ptr;
}
Though the deleter will usually be a lot like the above, this also gives the client the option of storing complex data structures and still getting them deleted correctly.

class Destructable
{
public:
virtual ~Destructable() {}
};
Instead of void *, store Destructable * in the pool. Make objects allocated from the pool inherit from Destructable.
Alternatively, override the operators new and delete for the relevant classes. Make them use the pool. Delete the object as soon as the CPU is done with it, in the regular way, in the code that owns it and hence knows its correct type; since the pool will not reuse the memory until it sees the appropriate frame end, whatever asynchronous hardware required you to lag garbage collection in this way can still do its thing.

The only way I could think of to do that would be to add a type entry to the FrameMemory struct, then use that to properly cast the memory for the delete. For example, if you have memory of type foo, you could have something like:
if (block[i].BlockType == BLOCKTYPE_FOO)
{
foo *theMemory = (foo *)block[i].pMemPtr;
delete theMemory;
}
Note that this can be an ****extremely**** dangerous operation if you do it wrong.

If you are mean stack frame (i.e. inside function)
you can try to use alloca()

First thing that I can think of is using boost::shared_ptr<void> (for the non-array version, some work may be required to adapt it for the array version) as the pointer type. And I think that should take care of mostly every detail. Whenever the frame is destroyed the memory will be appropriately deleted:
struct FrameMemory
{
uint32 frameIndex;
// bool allocatedType; //0 = new(), 1 = new[] only works with instances, not arrays
boost::shared_ptr<void> pMemPtr;
};
If you want to implement something similar manually, you can use a 'deleter' function pointer to handle the deletion of the objects, instead of calling delete directly. Here is a rough approach to how you could modify your code:
// helper deleter functions
template <typename T>
void object_deleter( void *p ) {
delete static_cast<T*>(p);
}
template <typename T>
void array_deleter( void *p ) {
delete [] static_cast<T*>(p);
}
class FrameMemory
{
public:
const uint32 frameIndex;
void* pMemPtr;
private:
void (*deleter)(void*);
public:
template <typename T>
FrameMemory( uint32 frame, T* memory, bool isarray = false )
: frameIndex(frame), pMemPtr(memory),
deleter( isarray? array_deleter<T> : object_deleter<T> )
{}
void delete() {
deleter(pMemPtr)
}
};
struct X;
void usage()
{
{
FrameMemory f( 1, new X );
f.delete();
}
{
FrameMemory f( 1, new x[10], true );
f.delete();
}
}
I would modify it further so that instead of having to call FrameMemory::delete() that was performed in the destructor, but that would take more time than I have right now to do correctly (that is, deciding how copies are to be handled and so on...

I would do something like this:
struct FrameMemoryBase
{
uint32 frameIndex;
bool allocatedType; //0 = new(), 1 = new[]
virtual void Free() = 0;
};
template <typename T>
struct FrameMemory : public FrameMemoryBase
{
void Free()
{
if(allocatedType == 0)
delete pMemPtr;
else if (allocatedType ==1)
delete[] pMemPtr;
}
T *pMemPtr;
};
which you would use via:
{
for(all blocks)
if(block[i].frameIndex == targetIndex)
block[i].Free();
}
If you also free the FrameMemory struct you could just change Free to a virtual destructor. I'm not sure this is what you're looking for since I don't understand what "I've attempted to find ways to use smart-pointer templated objects for the solution, but in order to do that, I have to overload the templated class to a non-templated base-type, which makes deletion even more difficult." means, but I hope this is helpful.
This requires that the memory management code somehow have access to the declarations of what you wish to free, but I don't think there's any way around that, assuming you want destructors called, which you explicitly do.

Related

Conditional declaration of objects inherting from a common base class to pass a reference to one of them

Say I have two classes inheriting from a common base, such as
class Thing{
public:
virtual void f()=0;
};
class Thing_variant_a: public Thing{
public:
void f(){
std::cout<<"I am (a)"<<std::endl;
}
};
class Thing_variant_b: public Thing{
public:
void f(){
std::cout<<"I am (b)"<<std::endl;
}
};
And a function taking a reference to a Thing object as an argument.
void function(Thing& t){
t.f();
}
Depending on conditions I would like to call function with either a thing_a or thing_b (and possibly extend this at some point adding another possibility of thing_c)
I know I can do this using a pointer
Thing *t = nullptr;
if(condition_a){
t = new Thing_variant_a();
} else if(condition_b){
t = new Thing_variant_b();
}
function(*t);
However, I would like to know if there is a better way, that
does not allocate heap memory
does not require me to take care of deleting t at some point (probably smart pointers, but I don't know much about those)
ensures I always pass a valid Thing reference to function (there might be more conditionals in a complicated structure than in this minimal example) I could do if(t){ function(*t);}else{/*handle error*/}), but it seems like there should be a more elegant solution.
If not all of the above are possible any combination of those?
This sounds very much like an XY problem. There is probably a different solution to your problem entirely.
C++ is a statically-typed language; that means types used in a given code path are fixed at compile-time. Dynamic types (types known at run time) are normally allocated via the heap or all-at-once and then selected at run time.
So not much is possible in your case as you've noticed..
You could for example just have two different code paths:
if (condition_a) {
Thing_variant_a a;
function(a);
} else if (condition_b) {
Thing_variant_a b;
function(b);
}
Preallocate the types:
Thing_variant_a a;
Thing_variant_a b;
if (condition_a) {
function(a);
} else if (condition_b) {
function(b);
}
Or use a template:
template<typename T>
void do_something() {
T t;
function(t);
}
// somewhere else in the code ...
do_something<Thing_variant_a>();
// or ...
do_something<Thing_variant_b>();
Here's a way using dynamic memory and unique_ptr:
std::unique_ptr<Thing> t;
if (condition_a) {
t = std::make_unique<Thing_variant_a>();
} else if (condition_b) {
t = std::make_unique<Thing_variant_b>();
}
function(*t);
// t is delete'd automatically at end of scope...
And by the way, a function like int f(){...} should return some int value.
Here is a way to do it without using the heap or pointers:
Thing_variant_a thingA;
Thing_variant_b thingB;
if(condition_a){
function(thingA);
} else if(condition_b){
function(thingB);
}
If you want, you reduce it to a single call via the ternary operator:
Thing_variant_a thingA;
Thing_variant_b thingB;
function(condition_a ? static_cast<Thing &>(thingA) : static_cast<Thing &>(thingB));
As far as references go, references in C++ are required to be always be non-NULL -- so if you try to dereference a NULL pointer (e.g. by calling function(*t) when t==NULL) you've already invoked undefined behavior and are doomed; there is nothing the code inside function() can do to save you. So if there is any change that your pointer is NULL, you must check for that before dereferencing it.
I'll try to answer each of your questions
does not allocate heap memory
Unfortunately c++ only supports polymorphism using pointers. I guess the problem you would face here is fragmented memory (meaning that your pointers are everywhere in the heap). The best way to handle that is to allocate the memory using a memory pool.
You could use an std::variant but you will still need to test for the currently available type in the variant.
does not require me to take care of deleting t at some point (probably smart pointers, but I don't know much about those)
You could use a std::unique_ptr which will basically called the destructor when no one holds that pointer anymore.
ensures I always pass a valid Thing reference to function (there might be more conditionals in a complicated structure than in this minimal example) I could do if(t){ function(*t);}else{/handle error/}), but it seems like there should be a more elegant solution.
If you use pointers your could just check for the nullptr as you are doing right now. I'm not sure what you are meaning by valid reference as a reference always points toward something and cannot be empty.

Can you use a member of deleter to keep alive a shared_ptr?

Given the following types
// interface and implementation used in one part of the codebase
struct Image
{
virtual std::vector<uint8_t>& GetData () = 0;
};
struct VecImage : public Image
{
std::vector<uint8_t> mData;
std::vector<uint8_t>& GetData () { return mData; }
};
// used in another part of the codebase
struct PtrImage
{
std::shared_ptr<uint8_t> mData;
PtrImage (std::shared_ptr<Image> pIm);
};
is the following constructor a sane and correct way to convert an Image to a PtrImage?
PtrImage::PtrImage (std::shared_ptr<Image> pIm)
{
struct im_deleter
{
std::shared_ptr<Image> keepAlive;
void operator () (uint8_t* ptr)
{
keepAlive.reset ();
}
};
mData = { &pIm->GetData()[0], im_deleter { pIm } };
}
PtrImage is used as a "value type", it is being passed around by value, while Image is passed around in shared_ptrs only.
is the following constructor a sane..
You extend lifetime of Image thanks to destructor, so data is still valid.
So you are correct on that point...
But, vector may reallocate, invalidating the buffer.
So resulting code is unsafe.
You could store std::shared_ptr<std::vector<uint8_t>> mData; to be safe.
.. and correct way
We have better/simpler with aliasing constructor of std::shared_ptr:
struct PtrImage
{
std::shared_ptr<std::vector<uint8_t>> mData;
PtrImage (std::shared_ptr<Image> pIm) : mData(pIm, &pIm->GetData()) {}
};
So ownership information PtrImage::mData is shared with pIm.
Note: I assumes that vector returned by GetData() has same (or longer) lifetime that Image (as for VecImage). if it is an unrelated vector (from other object), then you won't have solution.
As noted in comment, vector should not reallocate neither
Looks pretty dangerous to me:
std::shared_ptr<Image> i = std::make_shared<VecImage>(/* some data */);
PtrImage p(i); // has now stored a pointer to the vector's data
i->getData()->push_back(0); // repeat until re-allocation occurs!
What would p now hold? The shared pointer holds a pointer to the data that resided in the vector before re-allocation; but this data was replaced and got deleted. So you now have a dangling pointer stored in p (in the uint8_t pointer), using it (which will happen at latest when your smart pointer tries to delete its data) will result in undefined behaviour.
You should not even try to have a shared pointer guess whether it should delete its object or not. It you proceed that way, you will be caught at a time by a corner case or even if you managed to find all, by a new one created by an apparently unrelated change.
If you need to convert an Image to a PtrImage just say that you want to build a shared_ptr<T> from a T. There are 2 standard ways: a copy or a move, and in either the shared_ptr has ownership of its object.
In your example, as Image only returns a lvalue reference, you can only use a copy. You could have a move from a VecImage by taking ownership of its data member.

Why destructors does not accept parameters in C++?

Recently, I came across an example that my destructor needs to take a parameter.
I am working on a C package that manages memory internally and keeps track of allocating and freeing with parameters of its own. I do not want to break that.
I wrote a C code, that initializes my own data structures and frees them at the end. When I decided to migrate to C++ I realized that allocating data structures and freeing them should be placed in constructor and destructors. So I changed those functions to constructor and destructor.
My problem now is that I need to use a parameter to pass to destructor to free allocated data; that parameter is not in my own code and is C and I do not want to mess with that.
My question is twofold:
Why C++ decided not to accept parameters in destructors in the first place?
and
What are my options?
(I can save a pointer to that parameter or somehow call that function in my destructor, but it seems not a good practice of C++ programming)
Update: adding some code
Here is my imaginary class:
class paru_symbolic/* paru_symbolic*/
{
public:
paru_symbolic ( cholmod_sparse *A, cholmod_common *cc ); // constructor
~paru_symbolic (cholmod_common *cc ); // destructor
// -------------------------------------------------------------------------
// row-form of the input matrix and its permutations
// -----------------------------------------------------------------------
//--- other stuff
...
};
Here is my current C constructor:
#include "Parallel_LU.hpp"
paru_symbolic *paru_sym_analyse
(
// inputs, not modified
cholmod_sparse *A,
// workspace and parameters
cholmod_common *cc ){
DEBUGLEVEL(0);
...
aParent = (Int*) paru_alloc (m+nf, sizeof(Int),cc);
...
}
and destructor:
void paru_freesym (paru_symbolic **LUsym_handle,
// workspace and parameters
cholmod_common *cc
){
DEBUGLEVEL (0);
if (LUsym_handle == NULL || *LUsym_handle == NULL){
// nothing to do; caller probably ran out of memory
return;
}
paru_symbolic *LUsym;
LUsym = *LUsym_handle;
Int m, n, anz, nf, rjsize;
...
cholmod_l_free (m+nf, sizeof (Int), LUsym->aParent, cc);
...
cholmod_l_free (1, sizeof (paru_symbolic), LUsym, cc);
*LUsym_handle = NULL;
}
The parameter cc is used inside the SuiteSparse package for tracking allocations and freeing data. It has been used all over in SuiteSparse package and is a useful tool for tracking memory.
Some people mentioned that who wants to pass a parameter to the destructor.That is a fair point, but we could have the same parameters that we have in the constructor as a default.
Parameters in destructors do not make sense as destructors are automatically invoked when an object goes out of scope. How could you pass a parameter to that?
{
Foo x;
} // `~Foo()` is automatically called here
What you probably want is to store the resource in your class. Here's an unrealistic example with a dynamically-allocated pointer:
struct RAIIPointer
{
Foo* ptr;
// Initialize the resource
RAIIPointer() : ptr{new Foo{/*...*/}}
{
}
RAIIPointer(const RAIIPointer&) = delete;
RAIIPointer& operator=(const RAIIPointer&) = delete;
RAIIPointer(RAIIPointer&&) { /* implement appropriately */ }
RAIIPointer& operator=(RAIIPointer&&) { /* implement appropriately */ }
// Release the resource
~RAIIPointer()
{
delete ptr;
}
};
Note that in a real-world scenario you would use std::unique_ptr, and if you were implementing your own RAII resource class you would need to implement proper copy/move operations.
#Vittorio's answer has the general approach. I'll just tailor it to your added sample code.
The way you presented the issue is as follows:
You use a utility type cholmod_common to do some useful work for your type.
The instance of that type can be passed to several paru_symbolic objects you create.
No single instance of paru_symbolic owns it uniquely, but they all depend on it at the start and end of their lifetime. It must exist for the same duration as all of those objects.
That screams std::shared_ptr to me.
class paru_symbolic
{
std::shared_ptr<cholmod_common> _cc;
public:
paru_symbolic ( cholmod_sparse *A, std::shared_ptr<cholmod_common> cc)
: _cc(cc) {
// constructor
}
~paru_symbolic () {
// use _cc , it's guaranteed to live until the closing brace at the least.
}
};
That's it. The ownership is now shared. The last object that depends on the instance of cholmod_common will be the one to clean it up with no extra work from you.
In C++, this sort of thing is done via an allocator, see also std::allocator. So, you could create your own allocator with a cholmod_common* data member.
Alternatively, you can use the deleter parameter for memory management via smart pointers. For example
class foo
{
struct bar_deleter {
cholmod_common *cc;
bar_deleter(cholmod_common *c) : cc(c) {}
void destroy(bar*) { cc->free(bar); }
};
std::unique_ptr<bar,bar_deleter> data;
public:
foo(some_type const&input, cholmod_common *cc)
: data(cc->create<bar>(input), bar_deleter(cc)) {}
};
Which, of course, also keeps a cholmod_common* with the data.
The name "cholmod_common" suggests that this is a common resource, i.e. there is only one cholmod_common object at any given time. Iff this is so, then you could use a stateless allocator, which keeps the common resource as a static data member (or obtains it via a singleton).

How do I disallow or block the passing of stack allocated variables?

I have a class utilizing an std::forward_list like so:
void Foo::AddBar(Bar* _bar)
{
Bars.push_front(_bar);
}
void Foo::DeleteBar(Bar* _bar)
{
for (forward_list::iterator index = Bars.begin(); index != Bars.end(); ++index)
{
if (_bar == *index)
{
delete _bar;
forward_list.remove(_bar);
}
}
}
If I pass a stack allocated variable, in debug/release it will give me a runtime error, in production it will "mangle" the heap.
Bar bar;
foo.AddBar(&bar);
foo.DeleteBar(&bar); // Memory corruption on "delete _bar"
How do I prevent Foo::AddBar from accepting stack allocated data? Is there a better way to design this?
Edit 6/21/13
Containing the delete _bar; and forward_list.remove(_bar); inside the for loop, causes a runtime error when the iterator increments.
I've opted to keep ownership control entirely in Foo and using a template like so:
template<class T> T* AddBar()
{
Bar* object = new T();
Bars.push_front(object);
return object;
}
// Usage looks like...
Process* pid = foo.AddBar<MyBar>(); // adding a subclass of Bar
I'm using the pointer as a PID -- for lookup purposes. I could always return int to prevent the user from deleteing without first casting it. Oh, and for arguments I could do AddBar(void* arguments)
Simply put, you can not. Pointer is a pointer. You should avoid them in the first place. If you chose to use them, create a policy of documentation and make the code properly reviewed for it.
In your example transfer of ownership happens (or at least something halfway that part of design also stinks), you must document that. The function must be called with only objects that are created using certain ways. &bar must be caught on the review as violating that.
Change your interface and implementation to use unique_ptr.
While users can still wrap their stack pointer in unique_ptr, it is at least obvious that this is occuring.
struct Foo {
typedef std::vector< std::unique_ptr<Bar> > bar_storage;
bar_storage bars;
Bar* AddBar( std::unique_ptr<Bar> );
void DeleteBar( Bar* bar );
};
void Foo::AddBar(std::unique_ptr<Bar> bar)
{
Bars.push_back(std::move(bar));
}
void Foo::DeleteBar(Bar* bar)
{
for (bar_storage::iterator index = Bars.begin(); index != Bars.end(); ++index)
{
if (bar == *index)
{
Bars.erase(index);
}
}
}
what I have done is pushed the undefined behavior to the calling site, in particular:
Bar bar;
foo.AddBar(&bar); // does not compile
Instead, the caller is forced to:
foo.AddBar(std::unique_ptr<Bar>(&bar)); // user just did something really vulgar!
foo.DeleteBar(&bar); // Memory corruption on "delete _bar"
in particular, because your foo represents ownership of Bars, the adding of Bar to Foo should only be done by the code that already owned the Bar. Represent such sole-ownership as a std::unique_ptr<Bar> all the way back to creation, and those that you have the right to delete are unique_ptr, and those you don't are Bar*.

How to release pointer from boost::shared_ptr?

Can boost::shared_ptr release the stored pointer without deleting it?
I can see no release function exists in the documentation, also in the FAQ is explained why it does not provide release function, something like that the release can not be done on pointers that are not unique. My pointers are unique. How can I release my pointers ?
Or which boost smart pointer class to use that will allow me releasing of the pointer ?
I hope that you won't say use auto_ptr :)
Don't. Boost's FAQ entry:
Q. Why doesn't shared_ptr provide a release() function?
A. shared_ptr cannot give away ownership unless it's unique() because the other copy will still destroy the object.
Consider:
shared_ptr<int> a(new int);
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2
int * p = a.release();
// Who owns p now? b will still call delete on it in its destructor.
Furthermore, the pointer returned by release() would be difficult to deallocate reliably, as the source shared_ptr could have been created with a custom deleter.
So, this would be safe in case it's the only shared_ptr instance pointing to your object (when unique() returns true) and the object doesn't require a special deleter. I'd still question your design, if you used such a .release() function.
You could use fake deleter. Then pointers will not be deleted actually.
struct NullDeleter {template<typename T> void operator()(T*) {} };
// pp of type some_t defined somewhere
boost::shared_ptr<some_t> x(pp, NullDeleter() );
Kids, don't do this at home:
// set smarty to point to nothing
// returns old(smarty.get())
// caller is responsible for the returned pointer (careful)
template <typename T>
T* release (shared_ptr<T>& smarty) {
// sanity check:
assert (smarty.unique());
// only one owner (please don't play games with weak_ptr in another thread)
// would want to check the total count (shared+weak) here
// save the pointer:
T *raw = &*smarty;
// at this point smarty owns raw, can't return it
try {
// an exception here would be quite unpleasant
// now smash smarty:
new (&smarty) shared_ptr<T> ();
// REALLY: don't do it!
// the behaviour is not defined!
// in practice: at least a memory leak!
} catch (...) {
// there is no shared_ptr<T> in smarty zombie now
// can't fix it at this point:
// the only fix would be to retry, and it would probably throw again
// sorry, can't do anything
abort ();
}
// smarty is a fresh shared_ptr<T> that doesn't own raw
// at this point, nobody owns raw, can return it
return raw;
}
Now, is there a way to check if total count of owners for the ref count is > 1?
You need to use a deleter that you can request not to delete the underlying pointer.
See this answer (which has been marked as a duplicate of this question) for more information.
To let the pointer point to nothing again, you can call shared_ptr::reset().
However, this will delete the object pointed to when your pointer is the last reference to the object. This, however, is exactly the desired behaviour of the smart pointer in the first place.
If you just want a reference that does not hold the object alive, you can create a boost::weak_ptr (see boost documentation). A weak_ptr holds a reference to the object but does not add to the reference count, so the object gets deleted when only weak references exist.
The basis of sharing is trust. If some instance in your program needs to release the raw pointer, it is almost for sure that shared_ptr is the wrong type.
However, recently I wanted to do this too, as I needed to deallocate from a different process-heap. In the end I was taught that my older decision to use some std::shared_ptr was not thought-out.
I just routinely used this type for cleanup. But the pointer was just duplicated on a few places. Actually I needed a std::unique_ptr, which (suprise) has a release function.
Forgive them for they know not what they do.
This example works with boost::shared_ptr and msvs std::shared_ptr without memory leaks!
template <template <typename> class TSharedPtr, typename Type>
Type * release_shared(TSharedPtr<Type> & ptr)
{
//! this struct mimics the data of std:shared_ptr ( or boost::shared_ptr )
struct SharedVoidPtr
{
struct RefCounter
{
long _Uses;
long _Weaks;
};
void * ptr;
RefCounter * refC;
SharedVoidPtr()
{
ptr = refC = nullptr;
}
~SharedVoidPtr()
{
delete refC;
}
};
assert( ptr.unique() );
Type * t = ptr.get();
SharedVoidPtr sp; // create dummy shared_ptr
TSharedPtr<Type> * spPtr = (TSharedPtr<Type>*)( &sp );
spPtr->swap(ptr); // swap the contents
ptr.reset();
// now the xxx::shared_ptr is empy and
// SharedVoidPtr releases the raw poiter but deletes the underlying counter data
return t;
}
You can delete the shared pointer, which seems much the same to me. If pointers are always unique, then std::auto_ptr<> is a good choice. Bear in mind that unique pointers can't be used in STL containers, since operations on them do a lot of copying and temporary duplication.
I'm not entirely sure if your question is about achieving this, but if you want behaviour from a shared_ptr, where, if you release the value from one shared_ptr, all the other shared pointers to the same value become a nullptr, then you can put a unique_ptr in a shared_ptr to achieve that behaviour.
void print(std::string name, std::shared_ptr<std::unique_ptr<int>>& ptr)
{
if(ptr == nullptr || *ptr == nullptr)
{
std::cout << name << " points to nullptr" << std::endl;
}
else
{
std::cout << name << " points to value " << *(*ptr) << std::endl;
}
}
int main()
{
std::shared_ptr<std::unique_ptr<int>> original;
original = std::make_shared<std::unique_ptr<int>>(std::make_unique<int>(50));
std::shared_ptr<std::unique_ptr<int>> shared_original = original;
std::shared_ptr<std::unique_ptr<int>> thief = nullptr;
print(std::string("original"), original);
print(std::string("shared_original"), shared_original);
print(std::string("thief"), thief);
thief = std::make_shared<std::unique_ptr<int>>(original->release());
print(std::string("original"), original);
print(std::string("shared_original"), shared_original);
print(std::string("thief"), thief);
return 0;
}
Output:
original points to value 50
shared_original points to value 50
thief points to nullptr
original points to nullptr
shared_original points to nullptr
thief points to value 50
This behaviour allows you to share a resource (like an array), then later reuse that resource while invalidating all the shared references to this resource.
Here's a hack that might work. I wouldn't recommend it unless you're in a real bind.
template<typename T>
T * release_shared(std::shared_ptr<T> & shared)
{
static std::vector<std::shared_ptr<T> > graveyard;
graveyard.push_back(shared);
shared.reset();
return graveyard.back().get();
}
If your pointers are indeed unique do use std::unique_ptr or boost::scoped_ptr if the former is not available for your compiler. Otherwise consider combining the use of boost::shared_ptr with boost::weak_ptr. Check out the Boost documentation for details.
I am using Poco::HTTPRequestHandlerFactory which expects to return a raw HTTPRequestHandler*, the Poco framework deletes the handler once the request finishes.
Also using DI Sauce project to create the controllers, however the Injector returns shared_ptr which I cannot return directly, and returning handler.get() is no good either since the as soon as this function returns the shared_ptr goes out of scope and deletes then handler before its executed, so here is a reasonable (I think) reason to have a .release() method. I ended up creating a HTTPRequestHandlerWrapper class as follows :-
class HTTPRequestHandlerWrapper : public HTTPRequestHandler {
private:
sauce::shared_ptr<HTTPRequestHandler> _handler;
public:
HTTPRequestHandlerWrapper(sauce::shared_ptr<HTTPRequestHandler> handler) {
_handler = handler;
}
virtual void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) {
return _handler->handleRequest(request, response);
}
};
and then the factory would
HTTPRequestHandler* HttpHandlerFactory::createRequestHandler(const HTTPServerRequest& request) {
URI uri = URI(request.getURI());
auto path = uri.getPath();
auto method = request.getMethod();
sauce::shared_ptr<HTTPRequestHandler> handler = _injector->get<HTTPRequestHandler>(method + ":" + path);
return new HTTPRequestHandlerWrapper(handler);
}
which satisfied both Sauce and Poco and works nicely.
I needed to pass a pointer through async handlers and to keep the self-destruct behavior in case of failure but the final API expected a raw pointer, so I made this function to release from a single shared_ptr:
#include <memory>
template<typename T>
T * release(std::shared_ptr<T> & ptr)
{
struct { void operator()(T *) {} } NoDelete;
T * t = nullptr;
if (ptr.use_count() == 1)
{
t = ptr.get();
ptr.template reset<T>(nullptr, NoDelete);
}
return t;
}
If ptr.use_count() != 1 you shall get a nullptr instead.
Do note that, from cppreference (bold emphasis mine):
If use_count returns 1, there are no other owners. (The deprecated member function unique() is provided for this use case.) In multithreaded environment, this does not imply that the object is safe to modify because accesses to the managed object by former shared owners may not have completed, and because new shared owners may be introduced concurrently, such as by std::weak_ptr::lock.
Easy solution, increase the reference and then leak the shared_pointer.
boost::shared_ptr<MyType> shared_pointer_to_instance(new MyType());
new boost::shared_ptr<MyType>();
MyType * raw_pointer = shared_pointer_to_instance.get()
This will clearly cause a memory leak of both the shared_ptr and the MyType *