I have a class entity
that uses a stateful polymorphic allocator and std::unique_ptr
to manage a resource. Naturally, I have to provide a custom deleter for the unique_ptr that pairs with allocator_.new_object()
that I pass in the constructor. However, as this deleter must use the same allocator again, I need to access the allocator member from within the deleter. This appears to be quite tricky. Using this answer I was able to get this far, but now gcc complains that struct entity
is incomplete. Any way to get around this?
#include <string_view>
#include <cstdio>
#include <memory>
#include <memory_resource>
#include <type_traits>
struct StaticTimer_t
{
std::string_view hello_ = "Hello World!";
};
template <typename T> requires (std::is_pointer_v<T>)
auto deleter(T e) {
return [e](StaticTimer_t* p){ e->get_allocator().delete_object(p); };
}
struct entity
{
using allocator_t = std::pmr::polymorphic_allocator<std::byte>;
auto get_allocator() -> allocator_t
{
return allocator_;
}
entity(allocator_t allocator = {})
: allocator_( allocator )
, ptr_( allocator_.new_object<StaticTimer_t>(), deleter(this) )
{ }
auto print()
{
printf("%s\n", ptr_.get()->hello_.data());
}
allocator_t allocator_;
std::unique_ptr<StaticTimer_t, decltype(deleter<entity*>(nullptr))> ptr_;
};
int main()
{
entity e;
e.print();
}
Error:
<source>:14:38: error: invalid use of incomplete type 'struct entity'
14 | return [e](StaticTimer_t* p){ e->get_allocator().delete_object(p); };
| ~~~^~~~~~~~~~~~~
<source>:17:8: note: forward declaration of 'struct entity'
17 | struct entity
| ^~~~~~
Note: I'm looking for a way to get around std::function!
CodePudding user response:
Pass the allocator directly instead of the entity
. It is all you need and it is complete where you need it to be, unlike entity
.
using allocator_t = std::pmr::polymorphic_allocator<std::byte>;
auto deleter(allocator_t e) {
return [e](StaticTimer_t* p) mutable { e.delete_object(p); };
}
entity(allocator_t allocator = {})
: allocator_( allocator )
, ptr_( allocator_.new_object<StaticTimer_t>(), deleter(allocator_) )
{ }
std::unique_ptr<StaticTimer_t, decltype(deleter(std::declval<allocator_t>()))> ptr_;
Alternatively, replace the lambda with a struct (KamilCuk's answer).
CodePudding user response:
I'm looking for a way to get around std::function!
Write your own std::function that std::bind-s entity with a operator().
#include <string_view>
#include <cstdio>
#include <memory>
#include <memory_resource>
#include <type_traits>
#include <functional>
struct StaticTimer_t {
std::string_view hello_ = "Hello World!";
};
struct entity;
struct entityDeleter {
entity& e;
entityDeleter(entity& e) : e(e) {}
void operator()(StaticTimer_t *p);
};
struct entity {
using allocator_t = std::pmr::polymorphic_allocator<std::byte>;
auto get_allocator() -> allocator_t {
return allocator_;
}
entity(allocator_t allocator = {})
: allocator_( allocator )
, ptr_(
allocator_.new_object<StaticTimer_t>(),
entityDeleter(*this)
) {}
auto print() {
printf("%s\n", ptr_.get()->hello_.data());
}
allocator_t allocator_;
std::unique_ptr<StaticTimer_t, entityDeleter> ptr_;
};
void entityDeleter::operator()(StaticTimer_t *p) {
printf("deleter\n");
e.get_allocator().delete_object(p);
}
int main() {
entity e;
e.print();
}