In normal C++ design, most objects can be deleted either by a delete statement, the free function, or a library-specific equivalent to free. For such objects, the unique_ptr Deleter implementation can be a stateless object that is eliminated through Empty Base Class Optimization. However, some libraries require using another object (which might contain a function pointer or some other context) to delete objects from that library.
typedef struct lib_object lib_object;
struct lib_api {
lib_object (*createInstance)();
void (*freeInstance)(lib_object *o);
};
One could wrap this in unique_ptr by storing a lib_api pointer as a data member in a custom Deleter, but if multiple lib_object instances needed to be managed, e.g. in a container, it would double the memory overhead of tracking the objects. What kind of pattern can be used to maintain RAII principles when dealing with this library, while still remaining memory efficient?
If there is only ever one lib_api object, then you can have your deleter get a static pointer to it.
If there can be more than one lib_api object then you have no choice but to store a pointer to it in the Deleter.
I use a custom deleter template for such objects.
template<typename T, T Function>
struct function_deleter
{
template<typename U>
auto operator()(U&& u) const noexcept(noexcept(Function(std::forward<U>(u))))
{
return Function(std::forward<U>(u));
}
};
then you can have use your deleter call free:
unique_ptr<int, function_deleter<void(*)(void*), &free>> uniq;
And its size is still equal to one pointer. live demo
Come C++17 you'll be able to use auto for non-type template parameters, simplifying the code to:
template<auto Function>
struct function_deleter
{
template<typename U>
auto operator()(U&& u) const noexcept(noexcept(Function(std::forward<U>(u))))
{
return Function(std::forward<U>(u));
}
};
and
unique_ptr<int, function_deleter<&call_free>> uniq;
live demo
Having this, in your case I'd keep a unique_ptr<pair<lib_object, lib_api>> with static deleter supporting this structure.
using lib_pair = pair<lib_object, lib_api>;
void lib_free(lib_pair* p){
p->second.freeInstance(p->first);
delete p;
}
using unique_lib_ptr = unique_ptr<lib_pair, function_deleter<void(*)(lib_pair*), &lib_free>>
This seems more cache-heavy but might just be your thing.
There should exist a more elegant solution but I would write something like
template <class ContainerType>
class TObjectContainer : public ContainerType {
public:
TObjectContainer() = default;
TObjectContainer(const TObjectContainer&); // should call createCopy
TObjectContainer(TObjectContainer&&) = default;
~TObjectContainer()
{ for (lib_object* element : *this)
(*freeInstance)(element);
}
private:
void (*freeInstance)(lib_object *o);
};
typedef TObjectContainer<std::vector<lib_object*>> ObjectVector;
It does not use unique_ptr but it should basically do the job.
Note that your are likely to overload every removal method like clear to call freeInstance or pop_back to return your original std::unique_ptr.
Related
For educational sake I am trying to understand a bit how smart pointers works with custom deleters. So I've written this code on my own that simulates how std::uniqe_ptr works. In fact I also think about changing the deleters template functions into template function classes and specialize one for dynamic arrays. Anyway this is what I've tried:
template <typename T>
void Free(T* p)
{
std::cout << "Free(T*): Freeing memory of a dynamic object...\n";
delete p;
}
template <typename T>
void Del_It(T* p)
{
std::cout << "Del_It(T*): freeing memory of a dynamic object...\n";
delete p;
}
template <typename T, typename Deleter=void(*)(T*)>
class Uniptr
{
public:
Uniptr(T* = nullptr, Deleter = Free<T>);
virtual ~Uniptr();
private:
T* ptr_{nullptr};
Deleter delPtr_{nullptr};
};
template <typename T, typename Deleter>
Uniptr<T, Deleter>::Uniptr(T* p, Deleter d) :
ptr_(p),
delPtr_(d)
{
}
template <typename T, typename Deleter>
Uniptr<T, Deleter>::~Uniptr()
{
delPtr_(ptr_);
delPtr_ = nullptr;
}
int main()
{
Uniptr<int, void(*)(int*)> upi(new int(9), Del_It<int>);
std::cout << "\ndone\n";
}
It looks that it works fine but I need your advice, tips... Thank you
To be honest custom deleter can be everything. Let's make a dirty our hand,
int main()
{
auto f = [](FILE* f){std::fclose(f); std::cout<<"I am closing file\n";};
std::unique_ptr<FILE,decltype(f)>fptr{std::fopen("test.txt","w"), f};
}
What we have done here? We have wrapped the file handling in C via unique_ptr.
What we get it? In case of forget to close the file after the operation, we ensure that it will be closed automatically.
So that, do not think that custom deleter can only use to delete pointer. I can be specified for any application such as a socket, file, etc...
Please check that unique_ptr
Code was taken from File Wrapper
A custom deleter can used to perform some custom clean up operation when the unique pointer is destroyed. In your case you're not doing anything apart from deleting the pointer. Therefore you're not performing any custom clean up. Plus you've got two functions Free and Del_It that do the same thing. If Del_It is meant for dynamically-allocated arrays, it should do delete [] p.
Suppose you're working with legacy code that specifically requires you to call a release() function that frees resources:
class LegacyClass
{
...
void release() {...}
~LegacyClass() {...}
};
You can't change the legacy code (it might even be in shared library), but you have to call the release() function. So you could define a custom deleter to do that:
struct Deleter
{
void operator()(LegacyClass *ptr) const
{
if (ptr)
{
ptr->release();
delete ptr;
}
}
};
With a unique pointer the deleter is actually part of the type:
unique_ptr<T, Deleter>
but for a shared pointer the custom deleter is not part of the type; it's passed into the constructor. The custom deleter can be defined as:
functor
function pointer
lambda
std::function *
*(this one can bloat the size of your unique pointer)
I am writing a C++ wrapper around a C library. Here is an example of my strategy.
// header file
class LibrdfUri { // wrapper around librdf.h librdf_uri*
/*
* If the deleter of std::unique_ptr is an empty
* class then it can do some optimizations and
* not actually store the deleter object.
* Otherwise it has to accommodate extra space for
* the deleter, which is unnecessary
* https://stackoverflow.com/questions/61969200/what-is-the-purpose-of-wrapping-this-private-deleter-function-in-a-struct/61969274#61969274
*/
struct deleter {
// turns deleter into a functor. For passing on to unique_ptr
void operator()(librdf_uri *ptr);
};
// automate management of librdf_uri* lifetime
std::unique_ptr<librdf_uri, deleter> librdf_uri_;
public:
LibrdfUri() = default;
explicit LibrdfUri(const std::string& uri); // construct from string
librdf_uri *get(); // returns the underlying raw pointer
};
// implementation
void LibrdfUri::deleter::operator()(librdf_uri *ptr) {
librdf_free_uri(ptr); // this is the C library function for destruction of librdf_uri
}
LibrdfUri::LibrdfUri(const std::string &uri) {
// create pointer to underlying C library 'object'
librdf_uri_ = std::unique_ptr<librdf_uri, deleter>(
librdf_new_uri(World::getWorld(), (const unsigned char *) uri.c_str()) // World::getWorld is static. Returns a pointer required by librdf_new_uri
);
}
librdf_uri *LibrdfUri::get() {
return librdf_uri_.get();
}
// and is used like so:
LibrdfUri uri("http://uri.com");
librdf_uri* curi = uri.get(); // when needed
This works for the single type librdf_uri* which is a part of the underlying library however I have lots of these. My question is double barrelled. The first part concerns the best general strategy for generalizing this wrapper to other classes while the second is concerns the implementation of that strategy.
Regarding the first part, here are my thoughts:
1. I could implement each class manually like I've done here. This is probably the simplest and least elegant. Yet it still might be my best option. However there is a small amount of code duplication involved, since each CWrapper I write will essentially have the same structure. Not to mention if I need to change something then I'll have to do each class individually.
2. Use an base class (abstract?)
3. Use a template
The second part of my question is basically: if I implement either option 2 or 3 (which I think might even be just a single option) how would I do it?
Here is a (vastly broken) version of what I'm thinking:
template<class LibrdfType>
class CWrapper {
struct deleter { ; //?
void operator()(LibrdfType *ptr) {
// ??
};
}
std::unique_ptr<LibrdfType, deleter> ptr;
public:
CWrapper() = default;
LibrdfType *get() {
ptr.get();
};
};
Then, LibrdfUri and any other C class I need to wrap, would just subclass CWrapper
This is a better deleter:
template<auto f>
using deleter=std::integral_constant< std::decay_t<decltype(f)>, f >;
use:
deleter<librdf_free_uri>
is a stateless deleter that calls librdf_free_uri.
But we don't need that I think. Here is what I might do:
There are 3 pieces of information you need.
How to construct
How to destroy
What type to store
One way is to define ADL baser helpers with famous names that you override to delete/construct.
template<class T>struct tag_t{};
template<class T>constexpr tag_t<T> tag{};
template<class T>
void delete_wrapptr(T*)=delete;
struct cleanup_wrapptr{
template<class T>
void operator()(T* t)const{ delete_wrapptr(t); }
};
template<class T>
using wrapptr=std::unique_ptr<T, cleanup_wrapptr>;
template<class T>
wrapptr<T> make_wrapptr( tag_t<T>, ... )=delete;
now you just have to write overloads for make and delete.
void delete_wrapptr(librdf_uri* ptr){
librdf_free_uri(ptr); // this is the C library function for destruction of librdf_uri
}
librdr_uri* make_wrapptr(tag_t<librdf_uri>, const std::string &uri) {
return librdf_new_uri(World::getWorld(), (const unsigned char *) uri.c_str()); // World::getWorld is static. Returns a pointer required by librdf_new_uri
}
and you can;
wrapptr<librdf_uri> ptr = make_wrapptr(tag<librdf_uri>, uri);
the implementation becomes just overriding those two functions.
make_wrapptr and delete_wrapptr overloads you write need to be visible at creating point, and in the namespace of T, tag_t or cleanup_wrapptr. The implementations can be hidden in a cpp file, but the declaration of the overload cannot.
I'm trying to declare a lot of templatized Derived<T> objects that inherit from Base, and pushing them back in a std::vector<Base*>.
struct Base { ... };
template<typename T> struct Derived : Base { /* ctor(const string&) */ ... }
Derived<bool> online{"online"};
Derived<bool> official{"official"};
Derived<bool> noRotation{"no_rotation"};
Derived<bool> noBackground{"no_background"};
Derived<int> noSound{"no_sound"};
Derived<string> noMusic{"no_music"};
Derived<bool> blackAndWhite{"black_and_white"};
vector<Base*> configValues{&online,
&official,
&noRotation,
&noBackground,
&noSound,
&noMusic,
&blackAndWhite};
As you can see, the code is horrible. Is there any way to automate this without passing the vector as a const& in the Derived<T>::Derived<T>(...) constructor?
By automate I mean avoiding the repetition of the objects' names. I would like to fill a std::vector with all my Derived<T> objects without having to list them all manually.
(Macros accepted, but hopefully there's a better solution)
So lifetime is going to be one of the problems you face, and how this pattern is used in your program is another influence to the solution.
So supposing your Derived<> instances are not owned by the vector, then you need to ensure they outlive it. There are three basic approaches, which could be combined in some cases.
The first: Create a class which stores and populates the vector. If you have the same set of Derived<> types or parameters duplicated, this can at least 'deduplicate' your common structures. Then you can give those member functions to return or populate the vectors.
The second is to use std::tuple. Tuples could be useful if there are many parameter list variants and you want one instance to store all those Derived instances while having a way to create common routines (like filling the vector):
typedef std::tuple<
Derived<bool>,
Derived<bool>,
Derived<bool>,
Derived<bool>,
Derived<bool>,
Derived<int>,
Derived<std::string>,
Derived<bool>
> atuple;
atuple t{
"online",
"official",
"no_rotation",
"no_background",
"no_sound",
"no_music",
"black_and_white"
};
const size_t size(std::tuple_size<atuple>::value);
/* or you could use std::array because the size is constant. */
std::vector<Base*>configValues;
configValues.reserve(size);
push(t,configValues);
And push() would look like:
template<std::size_t I = 0, typename V, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
push(std::tuple<Tp...>& t, V&)
{ }
template<std::size_t I = 0, typename V, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
push(std::tuple<Tp...>& t, V& vec)
{
vec.push_back(&std::get<I>(t));
push<I + 1, V, Tp...>(t, vec);
}
(borrowed from iterate over tuple).
If you don't face this problem in multiple parts of your program, then these solutions will not be so useful to you.
The third - use arrays:
std::array<Derived<bool>,5> a{{{"online"},{"official"},{"no_rotation"},{"no_background"},{"black_and_white"}}};
Derived<int> noSound{"no_sound"};
Derived<string> noMusic{"no_music"};
vector<Base*> configValues{&noSound,&noMusic};
for (Derived<bool>& b:a) configValues.push_back(&b); // original order not retained
There seems to be two separate questions here...
The first question appears be that you do not want to pass a constant std::string to the constructor of Derived<T>. The only reason I can think of to do this is if the string needs to be modified while constructing a Derived<T> object. If you do not need to modify the string I recommend taking it by const reference like you are currently doing.
If you do need to modify the string in the constructor you can change the parameter to pass the string by either rvalue reference or by value.
Derived(std::string&& str) { /*...*/ } // Pass by r-value reference
Derived(std::string str) { /*...*/ } // Pass by value
Both will allow you to modify the string during construction.
As for the second question in you comment...
To fill the vector in the way described in your comment you can use uniform initialization. The only caveat is that you will need to use dynamic storage duration for the objects added to the vector.
std::vector<Base*> configValues{
{
new Derived<bool>{"online"},
new Derived<bool>{"official"},
new Derived<bool>{"no_rotation"},
new Derived<bool>{"no_background"},
new Derived<int>{"no_sound"},
new Derived<std::string>{"no_music"},
new Derived<bool>{"black_and_white"}
}
};
I'm not sure what your objective is so how you decide to manage the lifetime of those objects is up to you. I highly recommend using a smart pointer to manage their lifetime and ownership. For instance if you require shared ownership you could use std::shared_ptr like in the following example.
std::vector<std::shared_ptr<Base>> configValues{
{
std::shared_ptr<Base>(new Derived<bool>{"online"}),
std::shared_ptr<Base>(new Derived<bool>{"official"}),
std::shared_ptr<Base>(new Derived<bool>{"no_rotation"}),
std::shared_ptr<Base>(new Derived<bool>{"no_background"}),
std::shared_ptr<Base>(new Derived<int>{"no_sound"}),
std::shared_ptr<Base>(new Derived<std::string>{"no_music"}),
std::shared_ptr<Base>(new Derived<bool>{"black_and_white"})
}
};
Since std::initializer_list requires objects to be copyable you cannot use std::unique_ptr to manage the lifetime of the objects.
It sounds like you're going for a factory-pattern type of implementation, with a common container that all derived objects get added to.
Here's a working example to get you started (ideone):
#include <string>
#include <vector>
#include <memory>
#include <algorithm>
#include <iostream>
struct Base
{
typedef std::shared_ptr<Base> SharedPtr;
virtual ~Base(){}
virtual void print(){}
template<class T>
static SharedPtr makeDerived(const std::string& name);
static std::vector<SharedPtr> objs;
};
std::vector<Base::SharedPtr> Base::objs;
template<class T>
struct Derived : public Base
{
Derived(const std::string& name):name(name){}
void print(){std::cout<<name<<std::endl;}
std::string name;
};
template<class T>
Base::SharedPtr Base::makeDerived(const std::string& name)
{
SharedPtr p = std::make_shared<Derived<T> >(Derived<T>(name));
objs.push_back(p);
return p;
}
int main()
{
Base::makeDerived<bool>("online");
Base::makeDerived<int>("users");
std::for_each(Base::objs.begin(),Base::objs.end(),
[](Base::SharedPtr p){p->print();} );
}
shared_ptr ought to help with memory management. You can go with a static container or make an object to hold all your container, doesn't make a big difference.
Thanks for the answers, upvoted them all.
In the end I decided to create a "helper" class that dealt with ownership and creation.
From my GitHub SSVUtilsJson repo:
class Manager
{
private:
ssvu::MemoryManager<Base> memoryManager;
// MemoryManager internally has a vector<Base*> of owned pointers
public:
template<typename T> Derived<T>& create() { return memoryManager.create<Derived<T>>(); }
// MemoryManager::create<T> creates and stores a 'new T*' and returns a reference to it
};
Usage (from my GitHub SSVOpenHexagon repo)
Manager lvm;
auto& online (lvm.create<bool>());
auto& official (lvm.create<string>());
auto& noRotation (lvm.create<int>());
auto& noBackground (lvm.create<double>());
auto& noSound (lvm.create<char>());
auto& noMusic (lvm.create<void>());
for(Base* b : lvm.getItems()) { /* do something */ }
I am creating a class which interops with some Windows API code, now one of the pointers I have to initialize is done by calling a native function which initializes it.
My pointers are of type std::unique_ptr with a custom deleter, which calls the WinAPI deleter function provided, however I cannot pass the unique_ptr with the & address-of operator to the init-function. Why?
I have created a sample that demonstrates my problem:
#include <memory>
struct foo
{
int x;
};
struct custom_deleter {};
void init_foo(foo** init)
{
*init = new foo();
}
int main()
{
std::unique_ptr<foo, custom_deleter> foo_ptr;
init_foo(&foo_ptr);
}
The compiler barks and says:
source.cpp: In function 'int main()':
source.cpp:19:21: error: cannot convert 'std::unique_ptr<foo, custom_deleter>*' to 'foo**' for argument '1' to 'void init_foo(foo**)'
Somewhere under the covers, unique_ptr<foo> has a data member of type foo*.
However, it's not legitimate for a user of the class to directly modify that data member. Doing so would not necessarily preserve the class invariants of unique_ptr, in particular it wouldn't free the old pointer value (if any). In your special case you don't need that to happen, because the previous value is 0, but in general it should happen.
For that reason unique_ptr doesn't provide access to the data member, only to a copy of its value (via get() and operator->). You can't get a foo** out of your unique_ptr.
You could instead write:
foo *tmp;
init_foo(&tmp);
std::unique_ptr<foo, custom_deleter> foo_ptr(tmp);
This is exception-safe for the same reason that std::unique_ptr<foo, custom_deleter> foo_ptr(new foo()); is exception-safe: unique_ptr guarantees that whatever you pass in to its constructor will eventually get deleted using the deleter.
Btw, doesn't custom_deleter need an operator()(foo*)? Or have I missed something?
Steve has already explained what the technical problem is, however, the underlying problem goes much deeper: The code employs an idiom helpful when you deal with naked pointers. Why does this code do two-step initialization (first create the object, then initialize it) in the first place? Since you want to use smart pointers, I'd suggest you carefully adapt the code:
foo* init_foo()
{
return new foo();
}
int main()
{
std::unique_ptr<foo, custom_deleter> foo_ptr( init_foo() );
}
Of course, renaming init_foo() to create_foo() and having it return a std::unique_ptr<foo> directly would be better. Also, when you use two-step initialization, it's often advisable to consider using a class to wrap the data.
You can use the following trick:
template<class T>
class ptr_setter
{
public:
ptr_setter(T& Ptr): m_Ptr{Ptr} {}
~ptr_setter() { m_Ptr.reset(m_RawPtr); }
ptr_setter(const ptr_setter&) = delete;
ptr_setter& operator=(const ptr_setter&) = delete;
auto operator&() { return &m_RawPtr; }
private:
T& m_Ptr;
typename T::pointer m_RawPtr{};
};
// Macro will not be needed with C++17 class template deduction.
// If you dislike macros (as all normal people should)
// it's possible to replace it with a helper function,
// although this would make the code a little more complex.
#define ptr_setter(ptr) ptr_setter<decltype(ptr)>(ptr)
and then:
std::unique_ptr<foo, custom_deleter> foo_ptr;
init_foo(&ptr_setter(foo_ptr));
I eventually came up with an approach that allows to initialise unique_ptr's with a code like this:
struct TOpenSSLDeleter { ... }; // Your custom deleter
std::unique_ptr<EVP_MD_CTX, TOpenSSLDeleter> Ctx;
...
Ctx = MakeUnique(EVP_MD_CTX_create()); // MakeUnique() accepts raw pointer
And here is the solution:
template <class X>
struct TUniquePtrInitHelper {
TUniquePtrInitHelper(X *Raw) noexcept {
m_Raw = Raw;
}
template <class T, class D>
operator std::unique_ptr<T, D>() const noexcept {
return std::unique_ptr<T, D>(m_Raw);
}
private:
X *m_Raw;
};
template <class X>
TUniquePtrInitHelper<X> MakeUnique(X *Raw) noexcept {
return {Raw};
}
I have a std::list of boost::shared_ptr<T> and I want to remove an item from it but I only have a pointer of type T* which matches one of the items in the list.
However I cant use myList.remove( tPtr ) I'm guessing because shared_ptr does not implement == for its template argument type.
My immediate thought was to try myList.remove( shared_ptr<T>(tPtr) ) which is syntactically correct but it will crash from a double delete since the temporary shared_ptr has a separate use_count.
std::list< boost::shared_ptr<T> > myList;
T* tThisPtr = new T(); // This is wrong; only done for example code.
// stand-in for actual code in T using
// T's actual "this" pointer from within T
{
boost::shared_ptr<T> toAdd( tThisPtr ); // typically would be new T()
myList.push_back( toAdd );
}
{
//T has pointer to myList so that upon a certain action,
// it will remove itself romt the list
//myList.remove( tThisPtr); //doesn't compile
myList.remove( boost::shared_ptr<T>(tThisPtr) ); // compiles, but causes
// double delete
}
The only options I see remaining are to use std::find with a custom compare, or to loop through the list brute force and find it myself, but it seems there should be a better way.
Am I missing something obvious, or is this just too non-standard a use to be doing a remove the clean/normal way?
You're correct, we can't directly compare the pointers. But there does exist remove_if, and we can specify our own predicate. The solution:
template <typename T>
struct ptr_contains_predicate
{
ptr_contains_predicate(T* pPtr) :
mPtr(pPtr)
{}
template <typename P>
bool operator()(const p& pPtr) const
{
return pPtr.get() == mPtr;
}
T* mPtr;
};
template <typename T>
ptr_contains_predicate<T> ptr_contains(T* pPtr)
{
return ptr_contains_predicate<T>(pPtr);
}
Just keep the above predicate in a header somewhere, and you can use it wherever you want.
myList.remove_if(ptr_contains(tThisPtr));
The best solution is to never lose hold of the shared_ptr in the first place, so we can just use remove, but the above is harmless anyway.
std::list's remove_if member is what you need:
Define a predicate
template <typename T> struct shared_equals_raw
{
shared_equals_raw(T* raw)
:_raw(raw)
{}
bool operator()(const boost::shared_ptr<T>& ptr) const
{
return (ptr.get()==_raw);
}
private:
T*const _raw;
};
then you can call
myList.remove_if(shared_equals_raw(tThisPtr));
to have the list clean up nodes which have shared_ptrs to tThisPtr.
(Untested, so maybe some syntactic stuff needs fixing).
Michael Burr's advice re enable_shared_from_this is good though; it'd be better to avoid having the raw tThisPtr in play at all.
enable_shared_from_this can help with your problem, but it will require that the types you're using in the list derive from it:
http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/enable_shared_from_this.html
If the type enables that functionality, you can get the shared pointer from the object itself by calling shared_from_this().
Can you use the shared pointer to remove it?
std::list< boost::shared_ptr<T> > myList;
boost::shared_ptr<T> tThisPtr = new T();
{
myList.push_back(tThisPtr);
}
{
myList.remove(tThisPtr);
}