Generally speaking, in this crazy modern world full of smart pointers, I'm coming round to the fact that bald/bare pointers shouldn't be in method signatures.
I suppose there might be some cases where you need bald pointers for performance reasons but certainly I've always managed with references or references to smart pointers.
My question is this, can anyone suggest an automated way to enforce this? I can't see a way with clang, GCC or vera++
I think it is ok for non-owning raw-pointers to be used in method signatures. It is not ok to use "owning" raw-pointers.
For example this is quite ok:
void bar(const Widget* widget) {
if (widget)
widget->doSomething();
}
void foo() {
Widget w;
bar(&w);
}
If you want the Widget to be nullable you can't use a reference and using a smart pointer would be slower and not express the ownership model. The Widget can be guaranteed to be alive for the whole scope of foo. bar simply wants to "observe" it so a smart pointer is not needed. Another example where a non-owning raw-pointer is appropriate is something like:
class Node {
private:
std::vector<std::unique_ptr<Node>> children_; // Unique ownership of children
Node* parent_;
public:
// ...
};
The Node "owns" its children and when a Node dies its children die with it. Providing encapsulation of Node hasn't been broken, a Node can guarantee its parent is alive (if it has one). So a non-owning raw-pointer is appropriate for a back reference to the parent. Using smart pointers where they are not required makes code harder to reason about, can result in memory leaks and is premature pessimization.
If smart pointers are used throughout instead, all kinds of things can go wrong:
// Bad!
class Node {
private:
std::vector<std::shared_ptr<Node>> children_; // Can't have unique ownership anymore
std::shared_ptr<Node> parent_; // Cyclic reference!
public:
// Allow someone to take ownership of a child from its parent.
std::shared_ptr<Node> getChild(size_t i) { return children_.at(i); }
// ...
};
Some of these problems can be solved by using weak_ptr instead of shared_ptr but they still need to be used with care. A weak_ptr is a pointer that has the option of owning.
The point is to use the appropriate kind of pointer in the appropriate context and to have an ownership model that is as simple as possible.
And no, I don't think there is an automated way of enforcing this, it is part of the design. There are tricks you can use like Cheersandhth.-Alf said to try and enforce a particular class is used in the way you want by restricting access.
I don't know of any automated tool to do this, but such a check wouldn't be too hard to implement in cppcheck, which is open source and AIUI offers an easy way to add new rules.
I don't think it's a good idea to completely stay away from raw (bald, bare) pointers even for function arguments. But it can sometimes be a good idea to make sure that all instances of a certain type are dynamic and owned by smart pointers. This involves two measures:
Ensure (to the degree practical) that the type can only be instantiated dynamically.
Ensure (to the degree practical) that instantiation yields a smart pointer.
The first point is easy: just make the destructor non-public, and voilá, the few remaining ways to instantiate that type non-dynamically are not very natural. Any simple attempt to declare a local or namespace scope variable will fail. As will simple attempts to use that type directly as a data member type:
#include <memory>
template< class Type >
void destroy( Type* p ) { delete p; }
class Dynamic
{
template< class Type > friend void destroy( Type* );
protected:
virtual ~Dynamic() {}
};
//Dynamic x; //! Nope.
struct Blah
{
Dynamic x; //! Nope, sort of.
};
auto main()
-> int
{
//Dynamic x; //! Nope.
new Blah; //!Can't delete, but new is OK with MSVC 12...
}
Visual C++ 12.0 unfortunately accepts the above code as long as the out-commented statements remain out-commented. But it does issue a stern warning about its inability to generate a destructor.
So, Dynamic can only be created dynamically (without using low-level shenanigans, or ignoring that MSVC warning and accepting a memory leak), but how to ensure that every new instance is owned by a smart pointer?
Well you can restrict access to the constructors so that a factory function must be used. Another way to ensure use of the factory function is to define a placement allocation function, operator new, that an ordinary new-expression can't access. Since that's most esoteric and possibly non-trivial, and not of clear-cut value, the below code just restricts access to the constructors:
#include <memory> // std::shared_ptr
#include <utility> // std::forward
// A common "static" lifetime manager class that's easy to be-"friend".
struct Object
{
template< class Type >
static
void destroy( Type* p ) { delete p; }
template< class Type, class... Args>
static
auto create_shared( Args&&... args )
-> std::shared_ptr<Type>
{
return std::shared_ptr<Type>(
new Type( std::forward<Args>( args )... ),
&destroy<Type>
);
}
};
class Smart
{
friend class Object;
protected:
virtual ~Smart() {}
Smart( int ) {}
};
//Smart x; //! Nope.
struct Blah
{
//Smart x; //! Nope, sort of.
};
auto main()
-> int
{
//Smart x; //! Nope.
//new Blah; //!Can't delete.
//new Smart( 42 ); // Can't new.
Object::create_shared<Smart>( 42 ); // OK, std::shared_ptr
}
One problem with this approach is that the standard library's make_shared doesn't support a custom deleter, and shared_ptr doesn't use the common deleter of unique_ptr. One may hope that perhaps this will be rectified in future standard.
Disclaimer: I just wrote this for this answer, it's not been extensively tested. But I did this in old times with C++98, then with a macro for the create-functionality. So the principle is known to be sound.
The problem with this idea is that in the smart pointer world, T* is just a shorthand for optional<T&>. It no longer implies memory management, and as a result it becomes a safe idiom to identify an optional non-owned parameter.
Related
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.
Assume we have the following:
//! SomeClass.hpp
class
{
public:
SomeClass( void );
~SomeClass( void )
{
delete mFoo;
delete mBar;
}
...
private:
Foo* mFoo;
Bar* mBar;
StackObj mStackFoo;
};
//! SomeClass.cpp
SomeClass::SomeClass( void )
{
mFoo = new Foo;
mBar = new Bar;
mStackFoo = StackObj( ... );
}
Now, when we initialize the pointers, my understanding is that the constructor will create unnecessary copies of SomeClass' members, thus allocating and then deallocating memory simply for the sake of allocating memory.
It's common to use initializer lists, coupled with a separate initialization function (for heap allocated memory) as a method to avoid this. Say SomeClass has a private member function defined as void initHeapMem( void ). Then we can do,
SomeClass::SomeClass( void )
: mFoo( NULL ),
mBar( NULL ),
mStackFoo( ... )
{
initHeapMem();
}
void SomeClass::initHeapMem( void )
{
mFoo = new Foo;
mBar = new Bar;
}
Naturally, this somewhat fixes the problem. The issue here I believe is that there's still the overhead of another function call being performed.
The reason why we can't use initialization lists for raw pointers is because they're not thread safe. If something goes wrong, and the program throws an exception, there will still be a memory leak. Note: this is according to what I've read, my apologies if this is wrong.
So, with boost/C++11, we can use smart pointers from an #include <tr1/memory> directive in the header file ( assuming we're using STL ).
If we were to use, say, std::unique_ptr< T >, then we'd have Bar* mBar and Foo* mFoo replaced with:
std::unique_ptr< Foo > mFoo;
std::unique_ptr< Bar > mBar;
Which would then allow us to do,
SomeClass::SomeClass( void )
mFoo( new Foo ),
mBar( new Bar ),
mStackFoo( ... )
{
}
Since the smart pointer effectively wraps the memory allocation in its own constructor.
While this is a nice solution, I personally am not one to use smart pointers for every heap object I create, and I know there are others in the C++ community who feel the same way.
tl;dr
With all of that out of the way, what I'm really wondering is if there are any more efficient alternatives to initializing class members within an object (especially with the advent of C++11), apart from the ones I listed above.
unique_ptr is the right solution here. It has several advantages:
It explicitly documents ownership. One of the issues with raw pointers is that they don’t indicate anything about who owns them. With unique_ptr you have a single owner, and must explicitly move ownership should you want to transfer it.
It has essentially no overhead; the only thing unique_ptr does is invoke the deleter, which you were going to do anyway. Now you have the performance benefits of deterministic memory behaviour without the effort of manual memory management.
It makes thread- and exception-safety much easier to attain, thanks to RAII. That means less fretting about instruction order, and less explicit cleanup code. You get the benefits of exceptions without all of the problems that caused them to be avoided in so much C++03 code.
shared_ptr is in my experience needed much less often than unique_ptr. Shared ownership is useful mainly when you have an immutable resource such as a texture or audio file, where loading and copying are both expensive, but which you want to unload when it’s not in use. shared_ptr also imposes the overhead of added safety (thread-safety in particular) and reference counting.
The disadvantage, of course, is that smart pointers impose a syntactic overhead. They are not as “native” as raw pointers. For that, you have typedef, auto, decltype, and rolling your own convenience functions such as make_unique.
Why can't you do this?
SomeClass::SomeClass( void ) :
mFoo(new Foo)
, mBar(new Bar)
{
}
They are raw pointers and no unnecessary copies are created.
I should also point out that the reason you use initializer lists is so that the object is in a valid state (that is, all members have valid values) when the constructor body is executed.
SomeClass::SomeClass( void )
{
//before this point, mFoo and mBar's values are unpredictable
mFoo = new Foo;
mBar = new Bar;
}
Regarding exceptions, the destructor of SomeClass will not be called ONLY if the exception is thrown inside the constructor itself.
Finally, regarding being thread safe or not, it depends on whether each thread has its own copy of SomeClass or not and whether SomeClass contains static members that are being written to.
I wanted to make a special version of shared_ptr that would perform specific operations when it was created or destroyed, but my plans appear to be foiled by the realization that shared_ptr's destructor is non virtual, meaning when I override it, my pointers never get cleaned up when the last instance of them are destroyed.
The only alternative that comes to mind is to build in this behavior into every class that I want to use with my hypothetical custom shared_ptr, and that's not feasible (or possible in some cases).
Edit:
The reason I want this is because I want to use some classes as userdata objects in lua, and I want each one of my objects that I use this way to have a fenv table unique to it that will be cleaned up when all references to the object have been removed. I plan on using the address of the pointer as they key into a table that holds the fenv table.
Lets say I have a widget that can have other widgets as children. I create two widgets in Lua, then set one as the child of the other and remove all lua references to the child widget (the fact that it's a child is handled in C++). The GC can now run at any time and remove the child. I don't necessarily want the child to have it's destructor run though, so I want to make it a shared_ptr. That way, C++ objects can still use it after Lua has cleaned it up. If I've assigned values or functions to it's fenv I still want to be able to access them. Only when the final reference to my child widget is removed do I want the fenv tabled to be removed totally.
It already has this ability built in without the need to let people do dangerous things like derive from it:
#include <boost/shared_ptr.hpp>
#include <iostream>
/*
* Done as a function for simplicity.
* But this can be done in so many ways
*/
void MyCleanup(int* x)
{
std::cout << "DONE\n";
delete x;
}
int main()
{
boost::shared_ptr<int> x(new int(5), MyCleanup);
}
Problem with deriving:
Just off the top of my head.
class X: public shared_ptr<int> { /* STUFF. With a special destructor. */ };
int main()
{
/* what happens now? Similar to slicing but not quite */
X data1(new int(5));
shared_ptr<int> data2;
shared_ptr<int> data3(data);
data2 = data1;
}
Just make a wrapper object; much easier. You can have the wrapper object have a shared_ptr instance inside it, and still use the allocation address of the internal object as an index. This seems much better than mucking around with derivation or custom cleanup routines, unless I'm missing something.
Eg:
class CWrapsLuaObject
{
CWrapsLuaObject( LuaObject* pObject )
{ [assign internal ptr, do mapping, etc.] }
shared_ptr< LuaObject > m_spObject;
[...]
};
shared_ptr< CWrapsLuaObject > spInstance( new CWrapsLuaObject( pObject ) );
Am I missing why this would not be the easiest solution (not taking anything away from the other suggested solutions, which could also work)?
You can provide a custom deletion object to be used with the shared_ptr. If you're trying to stick extra information into the shared_ptr, you may be better putting it into the deletion object. It doesn't feel very clean to me, but it works.
class ExtraThingToDestroy
{
public:
~ExtraThingToDestroy() { std::cout<<"Destroying the extra thing"<<std::endl; }
};
template<typename T>
class CustomDestructor
{
public:
CustomDestructor( ExtraThingToDestroy * v ) : v_(v) {}
void operator()( T* t ) { delete t; delete v_; }
ExtraThingToDestroy * v_;
};
main()
{
shared_ptr<int> ptr( new int, MyExtraDestructor<int>( new ExtraThingToDestroy ) );
shared_ptr<int> ptr2 = ptr;
//Now when ptr and all its copies get destroyed,
// the ExtraThingToDestroy will get deleted along with the int.
}
if you derive the class your_shared_ptr from shared_ptr and override the destructor, your destructor should be called in code like this:
{
your_shared_ptr<int> x(new int);
}
If you use it like this, instead:
{
shared_ptr<int>* ptrptr = new your_shared_ptr<int>(new int);
}
then it won't, but do you really need that?
Or am I misunderstanding something?
Maybe I'm overcomplicating things, but then again, I do sort of like clean interfaces. Let's say I want a specialization of auto_ptr for an fstream - I want a default fstream for the generic case, but allow a replacement pointer?
template <>
class auto_ptr<fstream> {
static fstream myfStream;
fstream* ptr;
public:
auto_ptr() {
// set ptr to &myfStream;
}
reset(fstream* newPtr) {
// free old ptr if not the static one.
ptr = newPtr
};
}
Would you consider something different or more elegant? And how would you keep something like the above from propagating outside this particular compilation unit?
[The actual template is a boost::scoped_ptr.]
EDIT:
It's a contrived example. Ignore the fstream - it's about providing a default instance of object for an auto_ptr. I may not want to provide a specialized instance, but would like to keep the auto_ptr semantics for this static default object.
class UserClass {
public:
auto_ptr<fstream> ptr;
UserClass() { }
}
I may not provide an dynamic object at construction time - I still want it to have a meaningful default. Since I'm not looking at ownership-transfer semantics, it really shouldn't matter that my pointer class is pointing to a statically allocated object, no?
This wouldn't end up good. The biggest problem is that std::auto_ptr deletes the underlying object in its destructor. This means your default parameter can't be static. The only choice you can make is to do a lot of hacks there and IMHO the price you'll pay while maintaining all that crappy code isn't worth the small advantage you'd have.
That looks reasonable to me, could be confusing if it's use is widespread in a codebase and not documented though.
I notice you are being carful, but I'm going to stress it anyway: make sure you don't double-free your static object!
You might get something that compiles and works, but I wouldn't do that if I were you.
Boost defines certain functionality for the construction of an auto_ptr. If you redefine that somehow, you have violated their specification.
Invent a name for your new functionality, make it a factory function, and don't worry about specializing someone else's template.
EDIT: deriving from auto_ptr is another option, if you're really set on changing initialization semantics:
tempate < class T, T *d >
struct defaulted_auto_ptr
: public auto_ptr< T > {
defaulted_auto_ptr( T *p = d ) throw() : auto_ptr<T>( p ) {} // set default
defaulted_auto_ptr( auto_ptr<T> &r ) throw()
: auto_ptr<T>( r ) {} // allow conversion
template< class O > defaulted_auto_ptr( auto_ptr<O> &r ) throw()
: auto_ptr<T>( r ) {}
};
fstream default_file;
typedef defaulted_auto_ptr< fstream, &default_file > file_ptr;
auto_ptr< fstream > baseptr = file_ptr(); // can assign to auto_ptr, but unsafe
I'm a little doubtful of the cost-benefit tradeoff of this, but it's better than entirely reimplementing auto_ptr.
You still have to figure out what to do if a defaulted object is destroyed. default_file above will be deleted, potentially many times.
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?