C++11 中引入的这几个属性平常项目不常见,突然见到可能有点陌生,我挨个列举一下。
[[nodiscard]]
[[nodiscard]]
是 C++11 中引入的一个属性(attribute),用于向编译器发出警告,以确保编译器在某些情况下对函数的返回值进行检查,以避免出现可能导致错误或潜在问题的情况。
当你在函数声明之前使用 [[nodiscard]]
属性时,它会告诉编译器在调用该函数后,不要忽略返回值。如果忽略了带有 [[nodiscard]]
属性的函数的返回值,编译器会发出警告或错误。
例如,考虑以下示例代码:
[[nodiscard]] int CalculateSquare(int number) {
return number * number;
}
int main() {
CalculateSquare(5); // 警告:忽略了带有 [[nodiscard]] 属性的函数的返回值
return 0;
}
在上面的代码中,CalculateSquare
函数被标记为 [[nodiscard]]
,意味着它的返回值不应该被忽略。在 main
函数中,我们没有使用 CalculateSquare
的返回值,因此编译器会发出警告。
[[nodiscard]]
属性的使用可以帮助开发人员在编译时捕捉到一些可能导致错误的情况,例如忘记检查函数的返回值是否有效。这对于具有重要返回值的函数,如错误码、资源句柄等,非常有用。
需要注意的是,[[nodiscard]]
属性只是向编译器发出警告,具体的行为取决于编译器的实现。某些编译器可能会忽略该属性或提供其他扩展。因此,在使用 [[nodiscard]]
属性时,最好查阅特定编译器的文档以了解其行为和限制。
[[noreturn]]
[[noreturn]]
是 C++11 中引入的一个属性(attribute),用于告诉编译器一个函数不会返回到调用点,即函数在执行完毕后不会返回到调用者。
当你在函数声明之前使用 [[noreturn]]
属性时,它会告诉编译器该函数永远不会正常返回,例如像是执行了无限循环、抛出异常或调用了终止程序的函数(如 std::terminate
)。
这个属性的主要作用是帮助编译器进行代码优化和警告检查。编译器可以基于函数被标记为 [[noreturn]]
来进行一些优化,因为它知道该函数不会返回,从而提高代码的效率。此外,编译器还可以对带有 [[noreturn]]
属性的函数调用进行警告,以防止开发人员在调用这些函数之后继续执行代码。
以下是一个使用 [[noreturn]]
属性的示例:
[[noreturn]] void TerminateProgram() {
// 执行一些终止程序的操作
std::terminate();
}
int main() {
TerminateProgram(); // 警告:带有 [[noreturn]] 属性的函数不会返回
return 0;
}
在上面的示例中,TerminateProgram
函数被标记为 [[noreturn]]
,因为它在执行完毕后调用了 std::terminate
,这是一个终止程序的函数。在 main
函数中,我们调用了 TerminateProgram
,编译器会发出警告,因为它知道该函数不会返回。
需要注意的是,使用 [[noreturn]]
属性的函数必须确保在函数体内执行了终止程序的操作或者导致无限循环等不会返回的行为。如果函数带有返回语句或者没有明确的终止行为,使用 [[noreturn]]
属性是不正确的。
另外,需要注意的是,[[noreturn]]
属性只是向编译器提供信息,具体的行为和优化取决于编译器的实现。因此,在使用 [[noreturn]]
属性时,最好查阅特定编译器的文档以了解其行为和限制。
__attribute__((always_inline))
__attribute__((always_inline))
是 GCC 和 Clang 编译器提供的一个特性,用于强制编译器始终内联(inline)某个函数,即将函数的代码直接插入调用处,而不是通过函数调用的方式执行。
使用 __attribute__((always_inline))
属性修饰函数时,编译器将尝试将函数的所有调用点替换为函数体的实际代码。这可以减少函数调用的开销,提高程序的执行速度。然而,这也会导致编译生成的代码变大,因为函数体被复制到多个调用点。
下面是一个使用 __attribute__((always_inline))
的示例:
inline __attribute__((always_inline)) int Add(int a, int b) {
return a + b;
}
int main() {
int result = Add(3, 4);
return result;
}
在上面的示例中,Add
函数被标记为 __attribute__((always_inline))
,这会指示编译器始终内联该函数。编译器会尝试将 Add
函数的代码直接插入 main
函数中调用的地方,而不是生成一个函数调用。
需要注意的是,使用 __attribute__((always_inline))
属性时,编译器会尽可能地进行内联,但并不保证一定会内联函数。编译器可能会根据优化级别、函数大小、调用频率等因素进行决策。此外,这个特性是特定于 GCC 和 Clang 编译器的,不是标准的 C++ 特性,所以在使用时应注意可移植性。
另外,需要谨慎使用 __attribute__((always_inline))
,因为过度使用内联可能导致代码膨胀,增加可执行文件的大小,并可能降低缓存命中率。应该根据具体情况和性能需求来决定是否使用该属性。
__attribute__((visibility("hidden")))
__attribute__((visibility(value)))
是 GCC 和 Clang 编译器提供的一个特性,用于指定符号(函数、变量等)的可见性,即指定符号在链接过程中的可见范围。
这个特性可以用于控制符号在共享库(动态链接库)中的可见性,以及符号的导出和导入行为。它接受以下参数:
default
:默认可见性,符号在当前模块可见,但对于其他模块是隐藏的。hidden
:符号在当前模块可见,但对于其他模块是隐藏的。protected
:符号在当前模块可见,并且对于其他模块也是可见的。下面是一个示例:
void foo() __attribute__((visibility("hidden")));
int main() {
foo();
return 0;
}
在上面的示例中,foo
函数被标记为 __attribute__((visibility("hidden")))
,意味着该函数对于其他模块是隐藏的。它只能在当前模块(即同一共享库或可执行文件)内部使用,而无法被其他模块调用。
需要注意的是,__attribute__((visibility(value)))
特性的行为取决于编译器和平台。它主要适用于共享库的开发和使用,用于控制共享库中的符号的可见性。在使用时,应注意特定编译器的文档和平台相关的要求。
此外,对于跨平台的代码,应考虑使用更一般的方案来控制可见性,例如使用预编译指令,如 #ifdef
和 #ifdef
来定义不同平台下的符号可见性。
_Pragma("GCC optimize(\"Og\")")
_Pragma("GCC optimize(\"Og\")")
是一种使用预处理指令来控制编译器优化级别的方法。它是针对 GCC 编译器的特定语法。
通过 _Pragma
预处理指令,可以在代码中嵌入编译器特定的指令。在这个特定的例子中,"GCC optimize(\"Og\")"
是一个编译器指令,用于将优化级别设置为 "Og"
。"Og"
是 GCC 中的一个优化级别选项,表示启用优化,但只进行基本优化,不包括任何可能增加编译时间的优化。
下面是一个示例,展示了如何使用 _Pragma("GCC optimize(\"Og\")")
来设置优化级别:
#pragma GCC optimize("Og")
int main() {
// 一些代码
return 0;
}
在上面的示例中,通过使用 #pragma
预处理指令,将 _Pragma("GCC optimize(\"Og\")")
嵌入到代码中。这会告诉编译器在编译 main
函数时将优化级别设置为 "Og"
。
需要注意的是,_Pragma("GCC optimize(\"Og\")")
是特定于 GCC 编译器的语法,不是标准的 C++ 特性。因此,它可能不适用于其他编译器。
此外,优化级别的选择应该根据具体的需求和目标进行权衡。不同的优化级别可能会产生不同的结果,包括编译时间、可执行文件大小、执行速度等方面的差异。在选择优化级别时,应根据具体的应用场景进行评估和测试,以确定最合适的优化级别。
`noexcept` 是 C++ 中的一个关键字,用于指示函数是否可能抛出异常。
使用 `noexcept` 关键字可以将函数标记为不抛出异常的函数,或者指定函数可能抛出的特定异常类型。
1. `noexcept` 函数声明:
void func() noexcept;
在函数声明中使用 `noexcept` 关键字,表示该函数不会抛出任何异常。如果函数在运行时抛出了异常,`std::terminate` 会被调用终止程序。
2. `noexcept` 异常规格:
void func() noexcept(true);
void func() noexcept(false);
使用 `noexcept` 关键字的异常规格,可以指定函数是否可能抛出异常。`noexcept(true)` 表示函数不会抛出异常,而 `noexcept(false)` 表示函数可能抛出异常。
3. `noexcept` 运算符:
bool isNoExcept = noexcept(expression);
使用 `noexcept` 运算符可以判断一个表达式是否可能抛出异常。`noexcept(expression)` 返回一个 `bool` 值,表示 `expression` 是否可能抛出异常。如果 `expression` 是不抛出异常的表达式,则返回 `true`,否则返回 `false`。
使用 `noexcept` 关键字可以帮助程序员在编译时确定函数是否会引发异常,从而进行必要的错误处理或优化。然而,需要注意的是,`noexcept` 仅表示函数在正常情况下是否会抛出异常,不会检查函数中的未捕获异常或其他异常安全性问题。