在这种情况下,“忽略模板参数上的属性”是什么意思?

What does "ignoring attributes on template argument" mean in this context?

提问人:500 - Internal Server Error 提问时间:8/9/2023 最后编辑:Botje500 - Internal Server Error 更新时间:8/10/2023 访问量:196

问:

我的任务是消除一个庞大的 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、 和 都在标准标头中定义。opendirclosedirdirent.h

我知道这段代码是做什么的,而且它正在工作,但是警告是什么意思?编译器所引用的被忽略的属性是什么,其含义是什么?

C++ GCC-警告

评论

2赞 Alan Birtles 8/9/2023
请显示一个最小的可重现示例,包括编译器版本和编译器标志
2赞 Alan Birtles 8/9/2023
如果这是因为您的声明具有该属性,请参阅 stackoverflow.com/questions/73833602/...将其删除(或忽略/禁用警告)closedir__nonnull((1))
1赞 Jarod42 8/9/2023
一种“解决方法”(顺便说一句,可能更好)是创建一个自定义删除器类,而不是使用函数指针。
1赞 Jarod42 8/9/2023
“警告是什么意思?”函数指针没有该属性,因此它提供的任何检查(no_discard、检查非 null 参数等)都不会应用于函数指针调用。

答:

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_ptrclosedir

相反,首选自定义类型作为删除程序:

#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) 如果编译器不知道函数指针的确切值,则无法将函数指针优化为直接函数调用。众所周知,函数指针通常内联得很差。