提问人:500 - Internal Server Error 提问时间:8/9/2023 最后编辑:Botje500 - Internal Server Error 更新时间:8/10/2023 访问量:196
在这种情况下,“忽略模板参数上的属性”是什么意思?
What does "ignoring attributes on template argument" mean in this context?
问:
我的任务是消除一个庞大的 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
我知道这段代码是做什么的,而且它正在工作,但是警告是什么意思?编译器所引用的被忽略的属性是什么,其含义是什么?
答:
7赞
Jan Schultke
8/9/2023
#1
被忽略的属性可能是 GCC 的 nonnull
,这表示参数不能是 null 指针。您可以使用以下代码重现此警告:
#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) 如果编译器不知道函数指针的确切值,则无法将函数指针优化为直接函数调用。众所周知,函数指针通常内联得很差。
评论
closedir
__nonnull((1))