前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++17常用新特性(七)---新的属性和属性特性

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

作者头像
CPP开发前沿
发布2022-04-13 15:30:46
1.4K0
发布2022-04-13 15:30:46
举报
文章被收录于专栏:CPP开发前沿

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

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

  • 内存泄漏:在使用一些C语言的内存申请函数时,如malloc和realloc函数,如果使用时内存已经申请,但是没有对返回值进行恰当处理,可能会遗漏资源的释放,从而导致内存泄露。
  • 异常的奇怪的行为:如果没有对函数的返回值进行正确判断紧接着就进行了后面的操作,可能导致进程异常,如:获取对象实例的指针时,如果没有成功就在后面的代码中进行使用,就会导致进程异常。
  • 额外的开销:没有判断程序返回码从而做了一些额外的操作,造成资源的浪费。

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

代码语言:javascript
复制
[[nodiscard]] bool empty() const noexcept;

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

代码语言:javascript
复制
(void)empty();

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

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

2 [[maybe_unused]] 属性

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

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

  • 参数可能不被使用
代码语言:javascript
复制
void foo(int iVal, [[maybe_unused]] std::string strMsg)
{
}
  • 可能不被使用的类成员函数
代码语言:javascript
复制
class QuickStr{
private:
    char cKey;
    int iCount;
    [[maybe_unused]] char LargerCha[100];
};
  • 可以在函数声明时使用但是不能在执行语句前使用
代码语言:javascript
复制
[[nodiscard]] void* foo();

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

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

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

代码语言:javascript
复制
int main()
{
    int i=1;
    switch(i)
    {
        case 1:
            break;
        case 2:
        [[fallthrough]];
        case 3:
        [[fallthrough]];
        default:
        break;
    }
    return 0;
}

4 通用的属性扩展

  • 标记命名空间
代码语言:javascript
复制
namespace [[deprecated]] DraftAPI {
...
}
  • 标记枚举值
代码语言:javascript
复制
enum class Pet { 
    DOG = 0,
    CAT = 1,
    PIG = 2,
    bird [[deprecated]] = 3,
};

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

  • 使用 using 前缀

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

代码语言:javascript
复制
[[using MyLib: WebService, RestService, doc("html")]] void foo();

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

5 总结

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CPP开发前沿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档