The attribute which is being ignored is likely GCC's nonnull
, which indicates that parameters cannot be null pointers. You can reproduce this warning with the following code:
#include <memory>
void closedir(struct DIR*) __attribute__((nonnull(1)));
std::unique_ptr<struct DIR, decltype(&closedir)> dir(nullptr, &closedir);
<source>:5:48: warning: ignoring attributes on template argument 'void (*)(DIR*)'
[-Wignored-attributes]
5 | std::unique_ptr<struct DIR, decltype(&closedir)> dir(nullptr, &closedir);
|
The problem is that the attributes of a function pointer are discarded when being used as template arguments. If you kept using function pointers, you would have to get rid of the attribute (see Remove __attribute__((...)) from a function pointer or reference), or you would have to suppress the warning (see Selectively remove a warning message using GCC).
Solution
In general, you should not create smart pointers where the deleter is a function pointer, because that increases the size of the smart pointer1), and prevents optimizations2). You are creating a std::unique_ptr
that can hold a deleter with the same signature as closedir
, but the deleter could be any function in principle.
Instead, prefer custom types as deleters:
#include <memory>
// Exposition-only, obviously use #include <dirent.h>
void closedir(struct DIR*) __attribute__((nonnull(1)));
// Note 1: In C++20, you could also decltype(lambda) as a deleter type.
struct closedir_deleter {
// Note 2: Consider adding noexcept.
void operator()(struct DIR* d) const {
closedir(d);
}
};
// Note 3: You can create a type alias for this specialization of std::unique_ptr.
// Note 4: It is no longer necessary to pass a deleter as an argument to the
// constructor, because the deleter is default-constructible, and not a pointer.
std::unique_ptr<struct DIR, closedir_deleter> dir;
See live example at Compiler Explorer
Not only is this better practice, it also gets rid of the warning for you.
1) This is because std::unique-ptr
has to store the pointer itself, as well as the function pointer. For simple empty deleters, it doesn't have to store anything.
2) Function pointers cannot be optimized into direct function calls if the compiler doesn't know their exact value. Function pointers are known to be inlined poorly in general.