I have an Engine class which contains and owns some Systems. The Engine class has two containers, one map and one vector. Both keep pointers to the Systems.
The addSystem template function should add a pointer of a new System of the wanted type in the map and the addToPipeline should add a pointer of the System passed as a parameter in the vector. I used shared_ptrs for this but I am doing something wrong because I get a double free error if I use the addToPipeline function.
Here is the simplified Engine class:
class Engine
{
public:
template <class T>
T& addSystem();
void addToPipeline(System&);
private:
std::map<std::type_index, std::shared_ptr<System>> m_systems;
std::vector<std::shared_ptr<System>> m_pipeline;
};
void Engine::addToPipeline(System& sys)
{
m_pipeline.push_back(std::shared_ptr<System>(&sys));
}
template <class T>
T& Engine::addSystem()
{
std::shared_ptr<T> system = std::make_shared<T>();
auto inserted = m_systems.emplace(typeid(T),system);
return static_cast<T&>(*(*inserted.first).second);
}
The functions should be used like shown below:
auto& POSITION_SYSTEM = engine.addSystem<PositionSystem>();
engine.addToPipeline(POSITION_SYSTEM);
Any help is appreciated!
In this line:
m_pipeline.push_back(std::shared_ptr<System>(&sys));
You are creating a shared_ptr for an already managed object, since you already wrapped the same object in another smart pointer. So you end up with two reference counts for the same object, thus you get a double free.
This is not how shared_ptr should be used. Instead, you should return a shared_ptr from addSystem and take one as argument for addToPipeline:
void Engine::addToPipeline(std::shared_ptr<System> sys)
{
m_pipeline.push_back(sys);
}
template <class T>
std::shared_ptr<T> Engine::addSystem()
{
std::shared_ptr<T> system = std::make_shared<T>();
m_systems.emplace(typeid(T),system);
return system; // No need to use the return value of emplace
}
The idea with shared_ptrs is that instead of using bare pointers or references, you always pass a shared_ptr (unless ownership doesn't matter - then you can also pass a reference). You have to do it this way because the reference counter is managed by the smart pointers.
Edit: As rozina pointed out: Of course you can still pass references to the managed object, as long as nobody tries to delete the corresponding address. This might actually be preferable if other code is interested in using a certain object, but not concerned about ownership. For example, you might want to have a public interface which allows obtaining a reference to some object that's managed by a smart pointer internally. For example:
class Foo {
public:
Bar& getBar() {
return *m_bar;
}
private:
std::shared_ptr<Bar> m_bar;
};
This is perfectly fine as long as nobody does delete &aFoo.getBar() - which happens if you create a new shared_ptr with that reference, as you did in your original code.
Related
First, I know about unique_ptr and share_ptr, but I'm not using C++11 and thus I can't use them.
Every possible research from google returns a solution using those two smart pointers. I would like one without.
I need to pass ownership of a pointer to another class through the constructor.
PointerToPass* myPointer = new PointerToPass();
MyClass* myClass = new MyClass(myPointer);
So I could use raw pointers but I read everywhere that I should avoid it.
Using a reference is not an option.
I could use a smart pointer from Qt to show that I pass ownership like so:
QScopedPointer<PointerToPass> myPointer(new PointerToPass());
MyClass* myClass = new MyClass(myPointer.take());
This option clearly shows that the pointer is passed and that the ownership is given to myClass even if it's still using raw pointers.
Is there a better way to convey this idea?
It would be even better if it could be seen in the MyClass constructor signature.
What about clear indication pointer is not to be used outside?
class myClass {
public: myClass(PointerToPass*& p): _p(p) {
p = nullptr;
}
public: ~myClass() {
delete _p;
}
private: PointerToPass* _p;
};
PointerToPass* myPointer = new PointerToPass();
MyClass* myClass = new MyClass(myPointer);
std::cout << myPointer << "\n";
The C++ Core Guidelines has some advice about this and suggest you use owner from the Guideline Support Library (GSL) to annotate raw pointers.
template <class T>
using owner = T;
This is just a typedef of owner<T> to T. It serves only as annotation and would work for your constructor argument. If this syntax wasn't C++11.
We could use a similar idea instead though.
template<typename T>
struct owner
{
typedef T pointer;
};
MyClass(owner<PointerToPass*>::pointer p)
{
// ...
}
Similar to the technique in the guidelines, this doesn't actually enforce anything. It does annotate the code to make the ownership sematics clearer though.
I have read through many questions on SO on custom deleter for shared_ptr and unique_ptr, and the difference between the two. But, I still haven't found any clear answer to this question:
How can one best go about creating a type that acts as a shared_ptr with a custom deleter, similar to how unique_ptr has the deleter as part of the type definition?
For unique_ptr usage, I use a deleter class, that handles deletion of individual types (limiting it to just two types, for brevity):
struct SDL_Deleter {
void operator()( SDL_Surface* ptr ) { if (ptr) SDL_FreeSurface( ptr );}
void operator()( SDL_RWops* ptr ) { if (ptr) SDL_RWclose( ptr );}
};
using SurfacePtr = std::unique_ptr<SDL_Surface, SDL_Deleter>;
using RWopsPtr = std::unique_ptr<SDL_RWops, SDL_Deleter>;
Which can be used with something like
SurfacePtr surface(IMG_Load("image.png"));
And will call SDL_FreeSurface upon destruction.
This is all fine and well. However, how does one go about achieving the same for shared_ptr? Its type is defined as
template< class T > class shared_ptr;
and the way to provide a custom deleter is through the constructor. It doesn't feel right that the user of the shared_ptr wrapper needs to know which pointer type is wrapped, and how that pointer is supposed to be deleted. What would be the best way to achieve the same kind of usage as with the unique_ptr example of above.
In other words, that I could end up with:
SurfaceShPtr surface(IMG_Load("image.png"));
Instead of of something like
SurfaceShPtr surface(IMG_Load("image.png"),
[=](SDL_Surface* ptr){SDL_FreeSurface(ptr);});
Or, just slightly better
SurfaceShPtr surface(IMG_Load("image.png"),
SDL_Deleter());
Is there a way to do this, without having to create a RAII wrapper class (instead of a typedef), adding even more overhead?
If the answer is "this isn't possible". Why not?
The other answer provided here was that something close to what I asked could be done through function returns of unique_ptr with custom deleter, which can be implicitly converted to a shared_ptr.
The answer given was that a deleter defined as a type trait was not possible for std::shared_ptr. The answer suggested as an alternative, to use a function which returns a unique_ptr, implicitly converted to a shared_ptr.
Since this isn't part of the type, it is possible to make a simple mistake, leading to memory leaks. Which is what I wanted to avoid.
For example:
// Correct usage:
shared_ptr<SDL_Surface> s(createSurface(IMG_Load("image.png")));
// Memory Leak:
shared_ptr<SDL_Surface> s(IMG_Load("image.png"));
The concept I want to express is having the deleter as part of the type (which unique_ptr allows), but with the functionality of a shared_ptr. My suggested solution is deriving from shared_ptr, and providing the deleter type as a template argument. This takes up no additional memory, and works in the same way as for unique_ptr.
template<class T, class D = std::default_delete<T>>
struct shared_ptr_with_deleter : public std::shared_ptr<T>
{
explicit shared_ptr_with_deleter(T* t = nullptr)
: std::shared_ptr<T>(t, D()) {}
// Reset function, as it also needs to properly set the deleter.
void reset(T* t = nullptr) { std::shared_ptr<T>::reset(t, D()); }
};
Together with a deleter class (Thanks Jonathan Wakely. Way cleaner than my macro (now removed)):
struct SDL_Deleter
{
void operator()(SDL_Surface* p) const { if (p) SDL_FreeSurface(p); }
void operator()(SDL_RWops* p) const { if (p) SDL_RWclose(p); }
};
using SurfacePtr = std::unique_ptr<SDL_Surface, SDL_Deleter>;
using SurfaceShPtr = shared_ptr_with_deleter<SDL_Surface, SDL_Deleter>;
using RWopsPtr = std::unique_ptr<SDL_RWops, SDL_Deleter>;
using RWopsShPtr = shared_ptr_with_deleter<SDL_RWops, SDL_Deleter>;
Instances with SurfaceShPtr members are type guaranteed to clean up properly, the same as for SurfacePtr, which is what I wanted.
// Correct Usage (much harder to use incorrectly now):
SurfaceShPtr s(IMG_Load("image.png"));
// Still correct usage
s.reset(IMG_Load("other.png"));
I'll leave this up for a while, for comments, etc, without accepting the answer. Maybe there are even more dangerous caveats I've missed (having a non-virtual destructor not being one, as the parent shared_ptr is given charge of the deletion).
A typedef is a static, compile-time feature.
A deleter passed to a shared_ptr is a dynamic, run-time property. The deleter is "type-erased" and is not part of the shared_ptr interface.
Therefore you can't declare a typedef to represent an alternative deleter, you just pass one to the constructor.
What would be the best way to achieve the same kind of usage as with the unique_ptr example of above.
You could use functions to create the resources and return them in a shared_ptr
shared_ptr<SDL_Surface> create_sdl_surface(const char* s)
{
return shared_ptr<SDL_Surface>(IMG_load(s), SDL_FreeSurface);
}
But I would have those functions return a unique_ptr instead, which can be converted to shared_ptr, as below.
I would get rid of the macro and do something like this:
// type with overloaded functions for freeing each resource type
struct SDL_deleter
{
void operator()(SDL_Surface* p) const { if (p) SDL_FreeSurface(p); }
void operator()(SDL_RWops* p) const { if (p) SDL_RWclose(p); }
// etc.
};
// a unique_ptr using SDL_deleter:
template<typename P>
using SDL_Ptr = std::unique_ptr<P, SDL_deleter>;
// typedefs for the common ptr types:
using SurfacePtr = SDL_ptr<SDL_Surface>;
using RWopsPtr = SDL_ptr<SDL_RWops>;
// etc.
To answer the shared_ptr part of your question, define functions that create resources and return them in a SDL_ptr:
SurfacePtr createSurface(const char* s) { return SurfacePtr(IMG_load(s)); }
RWopsPtr createRWops([...]) { return RWopsPtr([...]); }
// etc.
Then you can easily create a shared_ptr from the result of those functions:
shared_ptr<SDL_Surface> s = createSurface("image.png");
The shared_ptr automatically acquires the right deleter from the unique_ptr.
My class has a pointer vector:
ptr_vector<Class> vec;
And in some "setup" method adds a few classes to the vector:
void setupOrSomething()
{
vec.push_back(new Class(...));
....
}
Now clients of this class may wish to add their Class objects to this classes list:
void addThingToMyList(Class *cPointer)
{
vec.push_back(cPointer);
}
And they may wish to remove them by passing the same pointer:
void removeThingFromMyList(Class *cPointer) { ... }
Now if I understand correctly, after reading this answer (https://stackoverflow.com/a/357043/48998), I need to implement that method as follows:
void removeThingFromMyList(Class *cPointer)
{
vec.release(std::find_if(vec.begin(),vec.end(),CheckPointerValue(cPointer)).release();
}
struct CheckPointerValue
{
CheckPointerValue(Class* c):cptr(c) {}
bool operator()(Class const& X) { return &X == cptr;}
private:
Class* cptr;
};
I understand I have to also call release() a second time on the auto_ptr that is returned from the ptr_vector.release().
Am I correct in assuming this will ensure that the caller of this method (RemoveThing...) will retain a valid reference to its Class object and that it will not be deleted? I simply want vec to gain a temporary ownership and then relinquish it.
Yes, they will retain a pointer to a valid instance. Of course they need to know that the pointer refers to a valid instance in the first place AND that a pointer to that instance is stored in the vector. If it's not, you will get undefined behavior and probably a seg fault.
I have template
template <class T>
class A
{
T* t_;
A(){t_ = new T();}
void SetItem(T& t)
{
t_ = t;
}
};
There are 2 cases with this template class
1. A<T> a;
2. A<T*> b;
If I invoke two times SetItem i.e.
a.SetItem(T());
a.SetItem(T());
memory will be cleaned properly?
same if I invoke like this:
b.SetItem(new T());
b.SetItem(new T());
I know that memory will not be cleaned.
Questions:
How to make constrain on template that it takes only T or T* ?
If I use template A<T*> how to prevent leaks. Should I modify class or take care of it outside?
Is there any way to make this work whenever I use A<T> or A<T*> ?
I think that use of smart pointers or auto pointers is an option. But I don't know for sure.
The quick answer is, it's up to the person using the class A to clear up heap allocated memory. If you use a std::list, and store pointers in it, then you (not the list) are responsible for calling delete on them. Don't try to make your templated container detect pointers and delete them.
I'd imagine if you use class A with a pointer template param then at some point you would call delete on the return from GetItem() (which I assume the class would provide).
(Also, SetItem should take a const T&.)
To avoid leaks, you should have destructor which will delete T when the object A is destroyed.
To enable your template to only take pointers you should use type traits. I'm not quite familiar enough with it to give you an example.
template <class T>
class A
{
T* t_;
//Set t_ to nullptr, as you are able to pass new T() to SetItem
A() : t_(nullptr) {}
~A() { delete t_; } // When A is destroyed, t_ will be deleted.
void SetItem(const T& t)
{
t_ = t;
}
};
A is a meaningless class here. The solutions to not make it leak are:
Use a smart pointer. If your object is going to be shared and you don't know the lifetimes, you can use shared_ptr. If it isn't and your A class owns the object, use unique_ptr.
Don't use a pointer at all but use an instance of T within your A. This puts restrictions on the type your class A may hold, but the users of your class can make it hold unique_ptr or shared_ptr by putting that in as the parameterized type. An example is vector which takes objects of type T but users can make their vectors take shared_ptr or unique_ptr.
You must specify if your class takes ownership if the user passes in a pointer. If so your class is really a smart pointer itself.
Which one to use is rather difficult to ascertain in your example as A has no purpose in its existing form.
I have a list of smart pointers. I want some of these smart pointers to act as regular pointers, meaning they are simply a reference to an instance and are not involved in its deallocation. They might for example point to instances allocated on the stack. The other smart pointers in the list should act as regular boost::shared_ptr.
Here is how the class might look:
template<class T> smart_ptr {
private:
T *p;
boost::shared_ptr<T> sp;
public:
smart_ptr(T *p): p(p), shared(0) { } // p will not be deleted
smart_ptr(boost::shared_ptr<T> &sp): p(sp.get()), sp(sp) { }
T *get() const { return p; }
}
If there is a boost class that does this, I would prefer to use it instead of writing a class myself. It appears there are none, or am I mistaken?
One constructor for shared_ptr takes the destructor method, and you can pass in an empty functor.
Using Custom Deallocator in boost::shared_ptr
(You want just an empty function.)
I've got this little class in my toolbox for this:
struct nodelete {
template <typename T>
void operator()( T * ) {}
};
Usage:
int main() {
SomeClass sc;
boost::shared_ptr<SomeClass> p( &sc, nodelete() );
// ...
}
This sounds like a boost::weak_ptr:
http://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/weak_ptr.htm
But you can only create a weak_ptr from a shared_ptr, so as for your stack-allocated objects, I'm not sure how that would work.
This smells of bad design.
I can't think of a reasonable situation where you wouldn't want to delete the pointer. Here are the (unreasonable IMO) situations:
1) static duration objects. Instead, consider using a singleton mixin (use CRTP to mixin the singleton that has an instance() method that returns a copy of a local static shared_ptr<>; local statics are thread unsafe so you'll also need an appropriate static mutex if this could be called by multiple threads). The benefit of using a proper singleton is that your singleton will be destructed at exit after other objects that continue to hold shared_ptr<>'s to it.
2) objects created on the stack. Just don't do this. Instead create the object on the heap protected by a shared_ptr<>. If you need to create shared_ptr<>'s to the object in different parts of the code (i.e. you can't take copies from an original shared_ptr<>) then inherit from boost::enable_shared_from_this<> and get shared_ptr<>'s from shared_from_this().
Is there some other reason you want a shared_ptr<> that doesn't ever delete anything?