C++标准中没有规定函数参数的求值顺序,也就是说,编译器可能会以任意顺序对参数进行求值.
1、问题分析:
- 如下代码, new Widget会分配一个Widget对象
- std::shared_ptr(new Widget) 会创建一个 std::shared_ptr 来管理这个 Widget 对象。
- priority() 是一个函数调用,可能会抛出异常。
如果 priority() 抛出异常,那么 std::shared_ptr 还没有接管 new Widget 分配的内存,因此这块内存将不会被释放,导致内存泄漏。
processWidget(std::shared_ptr<Widget>(new Widget), prioprity());
2、解决办法
2.1、语句分离
- 可以先将 std::shared_ptr 创建好,然后再调用 processWidget 函数。这样可以确保在调用 priority() 之前,std::shared_ptr 已经接管了 Widget 对象的内存管理,从而避免异常导致的内存泄漏。
#include <iostream>
#include <memory>
class Widget {
public:
Widget() { std::cout << "Widget constructed\n"; }
~Widget() { std::cout << "Widget destroyed\n"; }
};
int priority() {
// 假设这个函数可能会抛出异常
throw std::runtime_error("Priority error");
return 0;
}
void processWidget(std::shared_ptr<Widget> widget, int priority) {
std::cout << "Processing Widget with priority " << priority << "\n";
}
int main() {
try {
// 先将 std::shared_ptr<Widget> 创建好
std::shared_ptr<Widget> widget(new Widget);
// 然后再调用 priority() 和 processWidget
processWidget(widget, priority());
} catch (const std::exception& e) {
std::cerr << "Exception caught: " << e.what() << "\n";
}
return 0;
}
2.2、使用 std::make_shared 来创建 std::shared_ptr
- td::make_shared 会一次性分配内存并创建 std::shared_ptr,从而避免了在参数求值过程中可能发生的异常导致的内存泄漏。
#include <iostream>
#include <memory>
class Widget {
public:
Widget() { std::cout << "Widget constructed\n"; }
~Widget() { std::cout << "Widget destroyed\n"; }
};
int priority() {
// 假设这个函数可能会抛出异常
throw std::runtime_error("Priority error");
return 0;
}
void processWidget(std::shared_ptr<Widget> widget, int priority) {
std::cout << "Processing Widget with priority " << priority << "\n";
}
int main() {
try {
// 使用 std::make_shared 来避免内存泄漏
processWidget(std::make_shared<Widget>(), priority());
} catch (const std::exception& e) {
std::cerr << "Exception caught: " << e.what() << "\n";
}
return 0;
}
思维导图笔记:

1154

被折叠的 条评论
为什么被折叠?



