C++中noexcept的具体特性及其代码示例
文章目录
- 1. **作为异常说明符**
- 2. **作为运算符**
- 3. **性能优化**
- 4. **异常安全性**
- 总结
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
也可以帮助你提高代码的异常安全性,特别是在使用移动语义时。