-
Notifications
You must be signed in to change notification settings - Fork 4
Open
Description
for systems without exceptions enabled we need a way to call a concrete "init" method after the constructor when using the type-erasers in interface_ptr. The most generalized approach would use a lambda. For example:
template <typename Interface, typename PmrAllocator, typename... Args>
CETL_NODISCARD static InterfacePtr<Interface> make_unique_w_initializer(PmrAllocator alloc, std::function<bool(typename PmrAllocator::value_type&)>&& initializer, Args&&... args)
{
// Allocate memory for the concrete object.
// Then try to construct it in-place - it could potentially throw,
// so RAII will deallocate the memory BUT won't try to destroy the uninitialized object!
//
ConcreteRaii<PmrAllocator> concrete_raii{alloc};
if (auto* const concrete_ptr = concrete_raii.get())
{
concrete_raii.construct(std::forward<Args>(args)...);
if (not initializer(*concrete_ptr)) {
// Initializer failed. UNDO! UNDO!
concrete_raii.release();
}
}
// Everything is good, so now we can move ownership of the concrete object to the interface smart pointer.
//
return InterfacePtr<Interface>{concrete_raii.release(), PmrInterfaceDeleter<Interface>{alloc, 1}};
}
Here, the protocol is a pointer is passed into the init method iff allocation succeeds. If the init method returns nullptr then we destroy the object and return a nullptr in the InterfacePtr otherwise we continue normally. Use might look like:
struct MyType : public MyInterface {
bool Init() {
return true;
}
};
auto result = cetl::pmr::InterfaceFactory::make_unique_w_initializer<MyInterface>(concrete_allocator, [](MyType& p) { return p.Init(); });
Additional output from init can be obtained by using the lambda capture. Reliance on the SMO for std::function, of course, applies.
Metadata
Metadata
Assignees
Labels
No labels