我的任务是消除一个大型 C++ 项目中的警告,其中大部分不是我编写的,并且针对以下情况发出了更常见的警告之一:
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirToDelete.c_str()), closedir);
警告是
ignoring attributes on template argument 'int (*)(DIR*) {aka int(*)(__dirstream*)}' [-Wignored-attributes]
std::unique_ptr dir(opendir(dirToDelete.c_str()), closedir);
(
DIR
、opendir
和closedir
都在标准头dirent.h
中定义。)
我知道这段代码的作用,并且它正在工作,但是警告是什么意思?编译器引用的被忽略的属性是什么?这意味着什么?
被忽略的属性很可能是GCC的
nonnull
,这表明参数不能为空指针。您可以使用以下代码重现此警告:
#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);
|
问题是函数指针的属性在用作模板参数时会被丢弃。如果您继续使用函数指针,则必须删除该属性(请参阅从函数指针或引用中删除 __attribute__((...))),或者您必须抑制警告(请参阅选择性删除使用 GCC 的警告消息)。
解决方案1),并妨碍优化2)。您正在创建一个 std::unique_ptr
,它可以保存与
closedir
具有相同签名的删除器,但删除器原则上可以是任何函数。相反,更喜欢自定义类型作为删除器:
#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;
这不仅是更好的做法,它还为您消除了警告。
1) 这是因为std::unique-ptr
必须存储指针本身以及函数指针。对于简单的空删除器,它不必存储任何内容。
2) 如果编译器不知道函数指针的确切值,则无法将函数指针优化为直接函数调用。众所周知,函数指针的内联性能通常很差。