Vencat
Vencat

Reputation: 1622

use of std::function<> in template class

I came across below Queue template class,

template <class T>
class Queue {
protected:
    // Data
    std::queue<T> queue_;
    typename std::queue<T>::size_type size_max_;

    // Thread gubbins
    std::mutex mutex_;
    std::condition_variable full_;
    std::condition_variable empty_;

    // Exit
    std::atomic_bool quit_{false};
    std::atomic_bool finished_{false};

public:
    Queue(const size_t size_max);

    bool push(T &&data);
    bool pop(T &data);

    // The queue has finished accepting input
    void finished();
    // The queue will cannot be pushed or popped
    void quit();
};



using intQueue = Queue<std::unique_ptr<int, std::function<void(int*)>>>

and i don't understand the use of std::function<void(int*)> in above using statement. Why don't we write it as using intQueue = Queue<std::unique_ptr<int>> instead.

Upvotes: 0

Views: 102

Answers (2)

Patrick
Patrick

Reputation: 23629

There are actually 2 types of std::unique_ptr:

  • A unique pointer with a destructor that simply calls delete on the owned pointer
  • A unique pointer with a custom deleter

Although it is still one class template, both types of unique_ptr are not interchangeable. So a unique_ptr defined like std::unique_ptr<int> cannot be given a custom deleter, whereas std::unique_ptr<int, std::function<void(int*)>> CAN be given a custom deleter.

This is unlike std::shared_ptr, for which there is actually only 1 type (per pointee type of course). So you can have a type std::shared_ptr<Book> and still give it a custom deleter.

The reason why this difference is made for std::unique_ptr is to minimize memory consumption. In almost all cases the unique_ptr will use the default deleter, and so storing one pointer instead of 2 (the second for the deleter) is sufficient. Only in those cases where the class template is instantiated with a deleter-template-argument, the type will store 2 pointers.

EDIT: And of course, don't forget about Brian's remark below: the std::unique_ptr without custom deleter is also more efficient since the call to the deleter is 'hard-coded' and thus can be inlined, without having the overhead of a virtual call to the custom deleter. This makes this std::unique_ptr as efficient as calling delete yourself (without the risk of forgetting to call it).

Upvotes: 2

Caleth
Caleth

Reputation: 63117

std::function<void(int*)> is an object that can hold any "void(int*) function"-like value. Notably you can change a std::function object to hold different functions and function objects during it's lifetime.

It is used here as the (optional) Deleter type parameter for std::unique_ptr, which is used to retain knowledge of how to free the raw pointer held by the std::unique_ptr.

Adding these things together allows ints allocated by different means, requiring different deallocations, to be present in the same queue. This is a similar idea to the std::pmr containers.

Upvotes: 0

Related Questions