Sonic78
Sonic78

Reputation: 818

Use noexcept operator depenendet

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

Answers (2)

Sonic78
Sonic78

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

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275878

In this is as easy as:

~MyAllocator() noexcept(noexcept(std::declval<allocator_type&>().deallocate( memory_, allocator_ ))) {
  if (memory_ != nullptr) {
    allocator_.deallocate(memory_, length_);
  }
}

Live example.

But in 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_);
    }
  }

Live example.

So, upgrade to .

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

Related Questions