Which ctor of std::unique_ptr is used, when there is a user-defined deleter which is a function?

Following is excerpted from section 12.1.5 of text "C++ Primer", which contains text and code constructing `std::unique_ptr` with a user-defined deleter which is a function:
 
void end_connection(connection *p) { disconnect(*p); }


1
2
3
// p points to an object of type objT and uses an object of type delT to free that object
// it will call an object named fcn of type delT
unique_ptr<objT, delT> p (new objT, fcn);

As a somewhat more concrete example, we’ll rewrite our connection program to use a `unique_ptr` in place of a `shared_ptr` as follows:
1
2
3
4
5
6
7
8
9
void f(destination &d /* other needed parameters */)
{
connection c = connect(&d); // open the connection
// when p is destroyed, the connection will be closed
unique_ptr<connection, decltype(end_connection)*>
    p(&c, end_connection);
// use the connection
// when f exits, even if by an exception, the connection will be properly closed
}
//end of the excerpt.

According to my understanding of the text, the concrete form of the second template argument `decltype(end_connection)*` should be `void (*)(connection *)`. Then I checked the document for constructors of `std::unique_ptr` to try to learn to write my own unique_ptr-like class. The link of the document is: https://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr

My expectation of the ctor `std::unique_ptr<T,Deleter>::unique_ptr` should be as simple as `unique_ptr(T* p, Deleter d)` which will store `d` to a private data member of type `Deleter` which is a pointer to function type. This expectation is made by a simple literal correspondence: `T` is `connection` and `Deleter` is `decltype(end_connection)*`, or concretely `void (*)(connection *)`. But to my frustration, I couldn't find one in the document that is close to my expectation. The closest one is 3,4), but the type for deleter there are all references, left or right. So, can you please tell me which ctor of `std::unique_ptr` is used in the example, with a bit more details about how a pointer to function type is converted to the type of the deleter specified in the document? Thank you.
Last edited on
The code calls constructor 3 or 4.

When the cppreference page writes D in the explanation it actually means the second template parameter Deleter. The C++ standard calls the second template parameter D which is probably why it got mixed up.

If you read the explanation for constructor 3 and 4 you see that it's the signatures under a) that apply because Deleter is void(*)(connection *) (as you said) which is not a reference type. That means the signatures are:

unique_ptr(connection* p, void(*const& d)(connection*)) noexcept;
unique_ptr(connection* p, void(*&& d)(connection*)) noexcept;

When you pass end_connection as the second argument it's implicitly converted to a pointer which is an rvalue so this should call the && version if I'm not mistaken.
Last edited on
Topic archived. No new replies allowed.