• Index

标准属性

Reads: 10

标准属性

标准属性是用来对变量、函数、类等进行额外补充说明的,主要是让使用者知道一些信息,还有一些附加功能就是使编译器更好的优化和禁止一些警告等。

标准属性有以下这些:

  • [[noreturn]]:用于不返回的函数上。
  • [[carries_dependency]]:在线程操作中配合std::memory_order使用,优化性能。
  • [[deprecated]]:用于废弃的函数、变量、类等。
  • [[fallthrough]]:用于switch没有break;的时候禁止警告。
  • [[nodiscard]]:用它指定的类型用作函数返回类型,当不使用函数返回值时,编译时给出警告。
  • [[maybe_unused]]:用于没有使用的变量等,禁止警告。

标准属性都是[[属性名称]]这样的形式,一般的使用如下:

  • 函数:[[属性]] void func(void);
  • 变量:[[属性]] int value = 0;
  • 类、枚举、结构体、联合体:class [[属性]] testclass;

[[noreturn]]

当自己定义的函数不返回时,可以通过标准属性[[noreturn]]指示函数不返回。这个不返回,并不是想象中的只是返回类型指定voidvoid虽然不返回值,但是它算是一个返回,它的返回是return;

标准属性[[noreturn]]指示的函数是:绝不会正常结束并且不返回。例如:(以下情况都是在函数里没有return返回值的前提下)函数功能是无限循环、在函数正常结束前抛出异常等。

使用[[noreturn]]的注意事项:

  • 只能用在函数声明。
  • 有助于编译器进行编译优化。(因为函数不会正常结束,将函数安全结束的代码优化去掉。)
  • 当函数写了返回类型但不返回时,可以抑制编译器警告。(但可能编译器会出现另外一个警告说noreturn要与void返回类型配对。)
  • 当使用该属性但是却返回了值的时候,该行为未定义,即如果这样使用则运行时会有未知的问题。

基础示例

以下是完整的示例代码:

#include <iostream> // std::cout std::endl

[[noreturn]] void loop_print1(void) // 属性可以和函数名称同一行
{
    for (unsigned int i = 0;; ++i)
    {
        std::cout << i << std::endl;
    }
}

[[noreturn]]
void loop_print2(void) // 属性也可以和函数名称不同一行
{
    for (unsigned int i = 0;; --i)
    {
        std::cout << i << std::endl;
    }
}

int main(void)
{
    loop_print1();
    loop_print2(); // 由于上面函数是死循环, 所以这行永远都不会执行
    return 0;
}

至于属性和函数名称是否放在同一行,就看你的审美了。

[[deprecated]]

这个属性一般用于写第三方库的时候,这个属性可以用在类、自定义数据类型、变量、函数、枚举等。

在设计一个函数很久之后,发现这个函数写的并不完美,那么这时候可以改一下函数里面的定义。当再过一段时间发现这个函数名称和函数参数设计的不合理,那么这个时候就可能需要重新设计函数接口,而旧的函数就需要被废弃,让调用者不再调用这个函数。

属性[[deprecated]]可以用在变量、函数、类等地方上。

基础示例 1

属性[[deprecated]]只需要放在声明处即可。当调用废弃函数的时候,编译器会给出警告说函数已被废弃。

#include <iostream>

[[deprecated]]
void func(void);

int main(void)
{
    func();
    return 0;
}

void func(void)
{
}

基础示例 2

也可以注明废弃的详细信息。当编译的时候,编译器就会给出带废弃信息的警告信息。

#include <iostream>

[[deprecated("该函数已被废弃,请使用xxx函数代替")]]
void func(void);

int main(void)
{
    func();
    return 0;
}

void func(void)
{
}

[[fallthrough]]

属性[[fallthrough]]用在switch语句中,并且需要在case或者default的前面,用来给编译器说明:我是故意不用break;跳出switch的,我要让swtich继续执行向下执行,你不要给我报出警告。那么编译器就不会给出警告。

以下这段代码在编译的时候可能会出现警告信息:

int value = 1;
switch (value)
{
case 1:
    std::cout << "一" << std::endl;
case 2:
    std::cout << "二" << std::endl;
case 3:
    std::cout << "三" << std::endl;
default:
    std::cout << "嘿" << std::endl;
}

如果你确定你要的功能就是上面这样子,那就可以使用属性[[fallthrough]]来禁止这个警告。

#include <iostream>

int main(void)
{
    int value = 1;
    switch (value)
    {
    case 1:
        std::cout << "一" << std::endl;
        [[fallthrough]];
    case 2:
        std::cout << "二" << std::endl;
        [[fallthrough]];
    case 3:
        std::cout << "三" << std::endl;
        [[fallthrough]];
    default:
        std::cout << "其他" << std::endl;
    }
    return 0;
}

属性[[fallthrough]]需要放在case或者default的前面,并且也需要加上分号;

[[nodiscard]]

假设我们设计一个函数return_object,如果它的返回类型testclass是不能被丢弃忽略的,那么就可以使用属性[[nodiscard]]

#include <iostream>

class [[nodiscard]] testclass
{
};

testclass return_object(void)
{
    return testclass();
}

int main(void)
{
    // 以下调用函数由于没有使用变量保存返回值
    // 编译的时候就会报出警告提示你需要用变量保存返回值
    return_object();
    return 0;
}

[[maybe_unused]]

先给出使用方法:

#include <iostream>

int main(void)
{
    [[maybe_unused]] int a = 10086;
    return 0;
}

上面代码如果不使用属性[[maybe_unused]]的话,那么编译的时候编译器会给出警告说变量没有使用,使用属性[[maybe_unused]],编译器就不会给出警告了。不过建议当你的变量确实不用的话,就把它删了吧。


Comments

Make a comment

  • Index

WARNING: You are using an old browser that does not support HTML5. Please choose a modern browser (Chrome / Microsoft Edge / Firefox / Sarafi) to get a good experience.