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

500*_*ror 6 c++ gcc-warning

我的任务是消除一个大型 C++ 项目中的警告,其中大部分警告不是我编写的,并且针对以下内容发出了更常见的警告之一:

std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirToDelete.c_str()), closedir);
Run Code Online (Sandbox Code Playgroud)

警告是

ignoring attributes on template argument 'int (*)(DIR*) {aka int(*)(__dirstream*)}' [-Wignored-attributes]
std::unique_ptr dir(opendir(dirToDelete.c_str()), closedir);
Run Code Online (Sandbox Code Playgroud)

DIRopendir、 和closedir均在标准头文件中定义dirent.h。)

我知道这段代码的作用,并且它正在工作,但是警告是什么意思?编译器引用的被忽略的属性是什么?这意味着什么?

Jan*_*tke 10

被忽略的属性可能是GCC 的nonnull,它指示参数不能为空指针。您可以使用以下代码重现此警告:

#include <memory>

void closedir(struct DIR*) __attribute__((nonnull(1)));

std::unique_ptr<struct DIR, decltype(&closedir)> dir(nullptr, &closedir);
Run Code Online (Sandbox Code Playgroud)
<source>:5:48: warning: ignoring attributes on template argument 'void (*)(DIR*)' 
               [-Wignored-attributes]
    5 | std::unique_ptr<struct DIR, decltype(&closedir)> dir(nullptr, &closedir);
      |
Run Code Online (Sandbox Code Playgroud)

问题在于,函数指针的属性在用作模板参数时会被丢弃。如果您继续使用函数指针,则必须删除该属性(请参阅从函数指针或引用中删除 __attribute__((...))),或者您必须抑制警告(请参阅选择性删除警告消息使用海湾合作委员会)。

解决方案

一般来说,不应在删除器是函数指针的情况下创建智能指针,因为这会增加智能指针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;
Run Code Online (Sandbox Code Playgroud)

请参阅编译器资源管理器中的实时示例

这不仅是更好的做法,而且还可以消除警告。


1) 这是因为std::unique-ptr必须存储指针本身以及函数指针。对于简单的空删除器,它不必存储任何内容。

2) 如果编译器不知道函数指针的确切值,则无法将函数指针优化为直接函数调用。众所周知,函数指针的内联性能通常很差。