Reputation: 818
I wonder if it is possible to use C++11's noexcept operator to define the noextcept specifier of e. g. a destructor that calls a method of another class (e. g. std::allocator::deallocate):
template <class DelegateAllocator = std::allocator<uint8_t>>
class MyAllocator final {
public:
using allocator_type = DelegateAllocator;
// ...
~MyAllocator() noexcept(noexcept(/* what to use */))) {
if (memory_ != nullptr) {
allocator_.deallocate(memory_, length_);
}
}
private:
allocator_type allocator_;
uint8_t* memory_;
// ...
};
Questions: What is the best solution to define noexcept dependent to the used methods of a delegated type (e. g. std::allocator)? What has to be done - when possible - to use methods of a delegated type when different overloads exist (e. g. how would I use a specific deallocate implementation when not only one is provided)?
Upvotes: 0
Views: 86
Reputation: 818
This stack overflow answer pointed me to one solution:
~StackAllocator() noexcept(noexcept(std::declval<allocator_type>().*&allocator_type::deallocate)) {
if (memory_ != nullptr) {
allocator_.deallocate(memory_, length_);
}
}
This solution works as long as only one overload for the method exists. If anybody can provide a better solution (better to read, reusable ...) or a solution that works also with methods that have overloads please provide it.
Edit/Update: A colleague and the answer from Yakk below provided a better solution that also covers different overloads:
~StackAllocator() noexcept(noexcept(std::declval<allocator_type>().deallocate(std::declval<std::uint8_t*>(), std::declval<std::size_t>())))
{
if (memory_ != nullptr) {
allocator_.deallocate(memory_, length_);
}
}
Upvotes: 0
Reputation: 275878
In c++14 this is as easy as:
~MyAllocator() noexcept(noexcept(std::declval<allocator_type&>().deallocate( memory_, allocator_ ))) {
if (memory_ != nullptr) {
allocator_.deallocate(memory_, length_);
}
}
But in c++11 it is a pain to do "properly":
~MyAllocator() noexcept(noexcept(std::declval<allocator_type&>().deallocate( std::declval<uint8_t*&>(), std::declval<std::size_t&>() ))) {
if (memory_ != nullptr) {
allocator_.deallocate(memory_, length_);
}
}
So, upgrade to c++14.
You can also do it hackily:
~MyAllocator() noexcept(noexcept(std::declval<allocator_type&>().deallocate( (uint8_t*)nullptr,1 ))) {
but you have to be careful, because passing nullptr_t
could get you the wrong answer (hence the above cast from nullptr
to uint8_t*
, and avoiding using 0
as a literal).
Upvotes: 1