C++中noexcept的具体特性及其代码示例
【摘要】 1. 作为异常说明符 2. 作为运算符 3. 性能优化 4. 异常安全性 总结 1. 作为异常说明符noexcept可以放在函数声明或定义的后面,表示该函数不会抛出任何异常。如果函数在运行时抛出异常,程序会立即终止,并调用std::terminate()函数。特性:编译时检查:编译器会检查函数是否可能抛出异常。如果函数内部调用了可能抛出异常的代码,编译器会报错。运行时终止:如果标记为noe...
1. 作为异常说明符
noexcept
可以放在函数声明或定义的后面,表示该函数不会抛出任何异常。如果函数在运行时抛出异常,程序会立即终止,并调用std::terminate()
函数。
特性:
- 编译时检查:编译器会检查函数是否可能抛出异常。如果函数内部调用了可能抛出异常的代码,编译器会报错。
- 运行时终止:如果标记为
noexcept
的函数在运行时抛出异常,程序会立即终止。
代码示例:
#include <iostream>
#include <stdexcept>
void safeFunction() noexcept {
// 这个函数不会抛出异常
std::cout << "safeFunction called" << std::endl;
}
void unsafeFunction() {
// 这个函数可能会抛出异常
throw std::runtime_error("An error occurred");
}
int main() {
try {
safeFunction();
unsafeFunction(); // 这里会抛出异常
} catch (const std::exception& e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
}
return 0;
}
输出:
safeFunction called
Exception caught: An error occurred
如果将unsafeFunction
标记为noexcept
:
void unsafeFunction() noexcept {
// 这个函数可能会抛出异常
throw std::runtime_error("An error occurred");
}
输出:
safeFunction called
terminate called after throwing an instance of 'std::runtime_error'
what(): An error occurred
程序会立即终止,并调用std::terminate()
。
2. 作为运算符
noexcept(expression)
用于检查表达式是否可能抛出异常。如果表达式不会抛出异常,则返回true
;否则返回false
。
特性:
- 编译时检查:编译器会检查表达式是否可能抛出异常。
- 返回值:返回一个布尔值,表示表达式是否安全。
代码示例:
#include <iostream>
#include <stdexcept>
void safeFunction() noexcept {
std::cout << "safeFunction called" << std::endl;
}
void unsafeFunction() {
throw std::runtime_error("An error occurred");
}
int main() {
std::cout << "safeFunction noexcept: " << noexcept(safeFunction()) << std::endl;
std::cout << "unsafeFunction noexcept: " << noexcept(unsafeFunction()) << std::endl;
return 0;
}
输出:
safeFunction noexcept: 1
unsafeFunction noexcept: 0
3. 性能优化
标记为noexcept
的函数,编译器可以进行一些优化,例如删除异常处理代码、进行函数内联等,从而提高程序的性能。
代码示例:
#include <iostream>
#include <chrono>
void safeFunction() noexcept {
// 这个函数不会抛出异常
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
void unsafeFunction() {
// 这个函数可能会抛出异常
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
int main() {
auto start = std::chrono::high_resolution_clock::now();
safeFunction();
auto end = std::chrono::high_resolution_clock::now();
std::cout << "safeFunction took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl;
start = std::chrono::high_resolution_clock::now();
unsafeFunction();
end = std::chrono::high_resolution_clock::now();
std::cout << "unsafeFunction took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl;
return 0;
}
输出:
safeFunction took 100 ms
unsafeFunction took 100 ms
虽然在这个简单的例子中性能差异不明显,但在复杂的程序中,noexcept
可以显著提高性能。
4. 异常安全性
使用noexcept
可以提高代码的异常安全性。标记为noexcept
的函数不会抛出异常,因此调用这些函数的代码可以更加自信地使用不带RAII(资源获取即初始化)的代码。
代码示例:
#include <iostream>
#include <vector>
class MyClass {
public:
MyClass(int value) : value_(value) {}
int value() const { return value_; }
// 移动构造函数
MyClass(MyClass&& other) noexcept : value_(other.value_) {
other.value_ = 0;
}
// 移动赋值运算符
MyClass& operator=(MyClass&& other) noexcept {
if (this != &other) {
value_ = other.value_;
other.value_ = 0;
}
return *this;
}
private:
int value_;
};
void testMove() noexcept {
std::vector<MyClass> vec;
vec.reserve(10);
for (int i = 0; i < 10; ++i) {
vec.emplace_back(i);
}
std::vector<MyClass> vec2 = std::move(vec);
}
int main() {
testMove();
return 0;
}
在这个例子中,MyClass
的移动构造函数和移动赋值运算符都被标记为noexcept
,这使得std::vector
在进行内存重新分配等操作时可以安全地使用移动语义。
总结
noexcept
是一个非常有用的特性,它可以帮助你编写更安全、更高效的代码。通过标记函数为noexcept
,你可以告诉编译器这些函数不会抛出异常,从而让编译器进行优化。同时,noexcept
也可以帮助你提高代码的异常安全性,特别是在使用移动语义时。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)