how to deal with deallocation of copied pointers - c++

I'm trying to build a struct with a constructor and destructor in C++ (is that a bad thing to do? Should I use a class instead?), because I would hate to write unnecessary 10 lines of delete struct.member every time the members should be deallocated
The members of the struct are mostly pointers to other types.
However, apart from the option of the member pointer being a unique pointer, I also want to be able to assign a copy of another pointer to a member pointer in the struct. Consequently, if I try to deallocate that memory inside the destructor of the struct, it could have already been deallocated, causing a crash. (especially if the pointer copied was from another object of the same struct)
ptr to ptr-types instead of ptr-types in the struct wouldn't solve the problem either (I think), since I also want to allow the member to be able to be a unique pointer to an object.
A possible solution that I've thought of, is to have both a ptr-to-ptr and a ptr to be pointed to by the ptr-to-ptr. But that would just be rather inefficient.
What would my best solution be?
I hope (but doubt) my question is clear enough.
Here's some example code that might help.
struct GraphicsDesc
{
public:
ID3D11VertexShader* pSolidColorVS;
ID3D11PixelShader* pSolidColorPS;
ID3D11InputLayout* pInputLayout;
ID3D11ShaderResourceView* pColorMap;
ID3D11SamplerState* pSampler;
ID3D11BlendState* pBlendState;
ID3D11Buffer* pVertexBuffer;
UINT VertexSize;
D3D_PRIMITIVE_TOPOLOGY Topology;
GraphicsDesc()
{
pSolidColorVS = nullptr;
pSolidColorPS = nullptr;
pInputLayout = nullptr;
pColorMap = nullptr;
pSampler = nullptr;
pBlendState = nullptr;
pVertexBuffer = nullptr;
VertexSize = 0;
Topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
}
virtual ~GraphicsDesc()
{
if (pVertexBuffer) {
pVertexBuffer->Release();
}
if (pBlendState) {
pBlendState->Release();
}
if (pSampler) {
pSampler->Release();
}
if (pColorMap) {
pColorMap->Release();
}
if (pInputLayout) {
pInputLayout->Release();
}
if (pSolidColorPS) {
pSolidColorPS->Release();
}
if (pSolidColorVS) {
pSolidColorVS->Release();
}
}
};

All of those pointer data members are pointers to COM types that are reference counted. Release does not necessarily destroy the pointed-to object. It decrements the reference count and only destroys the object if there are no more references to it.
Rather than using raw pointers and calling AddRef and Release yourself, you should use CComPtr and CComQIPtr, which automate the reference counting.

Related

Pointing to an object that's going out of scope

I want to allocate an object of type custom_type_t (operator= is not available for this custom_type_t and I'm unable to modify that part of the codebase) depending on whether a condition is met and, if it's not met, that object should not be created at all.
I was initially thinking I could do:
// create the object even if it's not needed
custom_type_t object; // just use their default constructor which hopefully isn't expensive
if (condition_met) {
object = custom_type_t(constructor arguments);
}
However, this isn't possible because there's no operator=.
I'm wondering if there's a way in which I can do something like the following:
int* custom_type_t ptr;
if (condition_met) {
custom_type_t object = custom_type_t(constructor arguments);
ptr = &custom_type_t;
} // but object may go out of scope here, so ptr may end up pointing to garbage
// ptr will be used later on if condition_met == true
But I need to have object actually remain valid so ptr doesn't point to garbage?
Your problems/confusion seem to lie in separating the idea of creating an object from that of explicitly declaring that object. You can quite easily (conditionally) create your object, and subsequently use it, by just declaring a pointer to it.
Using a simple 'raw' pointer, something like this (for the sake of the example, I have assumed that two int values are required for the constructor arguments):
void function()
{
custom_type_t* pObject = nullptr;
if (condition_met) {
pObject = new custom_type_t(42, -9);
}
// ...
delete pObject; // If still nullptr, no problem - does nothing.
}
Or, better, using a smart pointer:
void function()
{
std::unique_ptr<custom_type_t> pObject;
if (condition_met) {
pObject = std::make_unique<custom_type_t>(42, -9);
}
//...
// "pObject" is automagically freed when this function returns.
}
In either of the above cases, you can use *pObject in expressions where you would otherwise use object, and you can use pObject->memberFunc() instead of object.memberFunc().

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.

c++ - Reference Counting garbage collection

Consider a simple class:
class MyInt {
public:
MyInt();
MyInt(const char *num);
};
I want to intergrate reference counting design pattern in to the class, which means i need to keep track of how much pointers point to an instance of this class. I need to implement it in this class only or create a different class and inherit it.
Given this example code i want to clear any allocated memory of the program:
int main() {
MyInt*a = new MyInt("10");
a = new MyInt("20");
delete a;
return 0;
}
My Tries
I tried operator oveloading of '=' and adding referenceCount member:
MyInt &MyInt::operator=(const MyInt* right) {
MyInt*left = this;
*this = right;
left->referenceCount -= 1;
if (left->referenceCount == 0) {
delete (left);
}
return *this;
}
But this does not work because we assign pointer of the class to another pointer.
Also tried to override the new and delete operators but can't seem to make it work and keep track of the number of pointer to an instance.
As it seems i need to implement four things: copy constructor, operator new, operator delete and operator =.
How can i effectivly keep track of the pointers and clear unpointed memory automaticly?
std::shared_ptr does exactly this. From the ref:
Manages the storage of a pointer, providing a limited
garbage-collection facility, possibly sharing that management with
other objects. [...] Once all shared_ptr objects that share ownership
over a pointer have released this ownership, the managed object is
deleted.
so I suggest you use this instead.
a is a pointer, so assigning to a will not involve MyInt::opterator= in any way. There is no way to detect when a pointer to T is assigned to by overloading T's operators. To do this, you would need to design a class type that behaves like a pointer. Then you could properly track when the pointer might leak an object and properly delete it. Fortunately for you, the standard library already provides this class. It's std::shared_ptr. Here is your example modified to use std::shared_ptr :
#include <memory>
struct InfInt {
InfInt(const char *) {}
};
int main()
{
auto a = std::make_shared<InfInt>("10");
a = std::make_shared<InfInt>("20"); // the previous `a` is deleted
// The object pointed to by `a` is automatically deleted when
// the last reference to it goes out of scope
return 0;
}

Correctly delete pointers in std::list allocated elsewhere [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Does std::list::remove method call destructor of each removed element?
I have a SpriteHandler class that allows the user to register a pointer to a Sprite object for drawing, all it does is access methods on the object. I wanted to write a safety catch that automatically deleted the memory associated with the pointers if the user forgot to do so by the end of the program (and it's less to worry about for the user too!) :
//SpriteHandler.h
class SpriteHandler {
public:
//...
void RegisterObject(Sprite* object);
bool IsRegistered(Sprite* object);
void UnregisterObject(Sprite* object);
private:
//...
static std::list<Sprite*>* _sprite = NULL;
};
//SpriteHandler.cpp
std::list<Sprite*>* SpriteHandler::_sprites = NULL;
void SpriteHandler::RegisterObject(Sprite* object) {
if(object == NULL) return;
if(_sprites == NULL) _sprites = new std::list<Sprite*>();
_sprites->push_back(object);
_sprites->sort(UDLessSprite);
}
bool SpriteHandler::IsRegistered(Sprite* object) {
return std::binary_search(_sprites->begin(), _sprites->end(), object);
}
void SpriteHandler::UnregisterObject(Sprite* object) {
if(object == NULL) return;
if(IsRegistered(object) == false) return;
_sprites->remove(object);
if(_sprites->size() <= 0) {
if(_sprites) {
_sprites->clear();
delete _sprites;
_sprites = NULL;
}
return;
}
_sprites->sort(UDLessSprite);
}
void SpriteHandler::Release() {
if(_sprites) {
std::list<Sprite*>::iterator _iter = _sprites->begin();
while(_iter != _sprites->end()) {
delete (*_iter);
(*_iter) = NULL;
++_iter;
}
_sprites->clear();
delete _sprites;
_sprites = NULL;
}
}
The issue I"m having is that after the first pointer is deleted the next iterator is pointing to an already freed object (memory location is 0xfeeefeee).
How would I correctly iterate through them, deleting each one?
If you want safety and implicit resource cleanup, do not use raw pointers, use smart pointers!
The problem with STL containers is:
If the contained object is a pointer STL containers DO NOT take ownership of destroying it.
You will have to explicitly call delete on each contained pointer to delete the content it is pointing to.
Have a look at this similar question here.
The best way to go about this is not storing raw pointers inside STL containers but using their intelligent cousins smart pointers instead(boost::shared_ptr) Check out the Boost documentation, These pointer cousins are intelligent enough to deallocate themselves when there is no one referring to them and saves you the problems like the one you are facing now.
There are a lot of things wrong with this code. But they all stem from this line:
std::list<Sprite*>* _sprite = NULL;
Unless you're using C++0x, this doesn't compile. You can't set the value of non-static members like this. Unless you intended for this to be static, and if you did, you should have used the static keyword.
But even worse is the fact that you're allocating a std::list on the heap. Why? You allocate one when you need it, and deallocate it in the destructor. Just make it a regular member variable.
C++ is not Java. Not everything has to be pointers.
If you are claiming ownership of these Sprite objects, you need to actually claim ownership of them. This would preferably be done with some kind of smart pointers. At a minimum, you should have a std::list<std::auto_ptr<Sprite> > This will ensure that the Sprite objects are deleted when you remove the entries from the list. If you have access to Boost (and if you don't, you need to get access to it) you can use boost::shared_ptr. C++0x offers much the same with std::shared_ptr.
std::auto_ptr only allows one object to own the pointer, while boost::shared_ptr allows shared ownership (hence the name). That's not necessary for your code (from what we can see at least), but it would not be a bad idea to allow shared ownership of Sprite objects. In C++0x, you should use std::unique_ptr instead of std::auto_ptr.
Either way, your code would now look like this:
//SpriteHandler.h
class SpriteHandler {
public:
//...
void RegisterObject(Sprite* object);
bool IsRegistered(Sprite* object);
void UnregisterObject(Sprite* object);
private:
//...
std::list<boost::shared_ptr<Sprite> > _sprite;
};
void SpriteHandler::RegisterObject(Sprite* object) {
if(!object) return;
_sprites.push_back(object);
_sprites.sort(UDLessSprite);
}
bool SpriteHandler::IsRegistered(Sprite* object) {
return std::binary_search(_sprites.begin(), _sprites.end(), object);
}
struct SpriteTester{
SpriteTester(Sprite *testValue) : _testValue(testValue) {}
bool operator()(const boost::shared_ptr<Sprite> &other) const{
return other.get() == _testValue;
}
Sprite *_testValue;
};
void SpriteHandler::UnregisterObject(Sprite* object) {
if(object == NULL) return;
_sprites.remove_if(object, SpriteTester(object));
//Deleting an entry cannot make the list unsorted.
}
void SpriteHandler::Release() {
_sprites.clear();
}
Notice that I introduced the SpriteTexture. This is because you cannot pass a Sprite* to std::list::remove now that we're using smart pointers. If you do, it will wrap it in a boost::shared_ptr temporary, thus causing the pointer to be deleted. This is bad, so I had to use a custom tester.
Also, if you want to have Sprite objects registered with a class, then the Sprite object constructor (or a factory method) should be doing this registering. The user should not be able to create unregistered Sprites.

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 *