C++17常用新特性(七)---新的属性和属性特性

983次阅读  |  发布于2年以前

C++17 增加了一些新的属性,这些属性并不是强制使用,但是正确使用后确实能够帮助我们避免一些问题,而这些问题恰恰是在做项目的时候容易忽略的,比较常见的一类问题是在前面把变量全部进行了定义,但是后面没有使用,还有一种是对于函数的返回值没有进行判断等,在本文中,将主要对C++17新增的一些属性进行解释和说明。

1 [[nodiscard]] 属性

[[nodiscard]]属性主要功能是可以让编译器在某个函数的返回值未被使用时进行告警,当然也可以不使用,或者使用后在后面的操作中也可以忽略这种警告。在实际编码时下面这三种场景是使用[[nodiscard]]性价比最高的地方:

针对上面的场景,参考代码如下:

[[nodiscard]] bool empty() const noexcept;

如上,在判断为空的函数前使用了该属性,如果在后面的使用时没有对返回值进行判断,编译器就会告警。当然在实际的使用中如果不想进行告警,还可以强转接口的返回值为void。从而避免编译器告警。

(void)empty();

另外,在实际编程时,判断是否为空的下一步如果不为空可能就会直接调用清理函数对资源进行回收。但是如果没有判断返回值,就会对空的资源进行清理清理,从而造成程序的额外操作,造成不必要的开销,同理,如果是获取指针,没有判断指针是否为空就直接使用,将会造成严重的后果。

在使用[[nodiscard]]属性时,如果在类里使用了该属性的成员函数被覆盖时如果没有在派生类中再次标记将不会生效,这一点也是在使用时需要注意的地方。

2 [[maybe_unused]] 属性

[[maybe_unused]] 可以抵消[[nodiscard]] 属性产生的效果,主要功能是避免编译器在某个变量未被使用时产生告警。该属性可以应用于类的声明、使用typedef 或者 using 定义的类型、变量、非静态数据成员、函数、枚举类型、枚举值等场景。

具体效果如下面代码所示:


void foo(int iVal, [[maybe_unused]] std::string strMsg)
{
}
class QuickStr{
private:
    char cKey;
    int iCount;
    [[maybe_unused]] char LargerCha[100];
};

[[nodiscard]] void* foo();

int main()
{
    [[nodiscard]] foo();
    return 0;
}

代码执行后,编译器错误为:

3 [[fallthrough]] 属性 [[fallthrough]] 属性主要功能是可以让编译器帮忙检查在switch语句中没有使用break时避免产生告警。如下代码所示:

int main()
{
    int i=1;
    switch(i)
    {
        case 1:
            break;
        case 2:
        [[fallthrough]];
        case 3:
        [[fallthrough]];
        default:
        break;
    }
    return 0;
}

4 通用的属性扩展

namespace [[deprecated]] DraftAPI {
...
}
enum class Pet { 
    DOG = 0,
    CAT = 1,
    PIG = 2,
    bird [[deprecated]] = 3,
};

如上,枚举值bird已经被标记废弃。

实际编程时,用户会自定义命名空间,并包含自己定义的一些属性,这些属性在引用时通常需要加上自定义的命名空间,C++17后就可以简化来写了。前提是使用using标记。如下代码所示:

[[using MyLib: WebService, RestService, doc("html")]] void foo();

如果已经使用了using,在后面的自定义属性中继续加上命名空间的话编译将会报错。

5 总结

本文中的三个新属性由 Andrew Tomazos在https://wg21.link/p0068r0中首次提出。

- EOF -

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8