在以下代码中:
$filename = "Registrations.csv";
$fp = fopen('php://output', 'w');
$header = array("Sr No","FirstName","RegNo","Address","Contact","email");
header('Content-type: application/csv');
header('Content-Disposition: attachment; filename='.$filename);
fputcsv($fp, $header);
$query = "select FirstName,RegNo,Address,Contact,email from Registration";
$result = mssql_query($query);
while($row = mssql_fetch_row($result)) {
fputcsv($fp, $row);
}
exit;
在调用#include <memory>
#include <iostream>
void mydeallocator(int * x) {
std::cerr << "Freeing memory" << std::endl;
delete x;
}
struct Foo {
std::unique_ptr <int,std::function <void(int*)>> x;
Foo(bool fail) : x(new int(1),mydeallocator) {
if(fail)
throw std::runtime_error("We fail here");
}
};
int main() {
{auto foo1 = Foo(false);}
{auto foo2 = Foo(true);}
}
时,似乎没有正确释放内存。也就是说,当我们编译并运行该程序时,我们得到了结果:
Foo(true)
我相信消息Freeing memory
terminate called after throwing an instance of 'std::runtime_error'
what(): We fail here
Aborted
应该被调用两次。基本上,根据这个question和ISO C ++人员here和here,我的理解是堆栈应该在Freeing memory
和Foo
的构造函数上展开。应该调用它的析构函数,它应该调用x
。当然,这不会发生,为什么内存没有被释放?
答案 0 :(得分:21)
当您无需重新抛出时,您的原始代码throw;
。这导致std::terminate
被调用;堆栈没有解开(因此析构函数不会运行)。
您的新代码会抛出异常而不处理它。在这种情况下,堆栈是否被展开是实现定义的,因此它仍然完全符合terminate()
。 [except.terminate],强调我的:
在某些情况下,必须放弃异常处理 微妙的错误处理技术。 [注意:这些情况是:
- 当异常处理机制完成异常对象的初始化之后但在激活之前 异常处理程序(15.1),调用一个通过一个退出的函数 例外,或
- 当异常处理机制找不到抛出异常的处理程序(15.3)或
时- 当搜索处理程序(15.3)遇到函数的最外面的块时,noexcept-specification不允许 例外(15.4)或
- 当堆栈展开期间对象的销毁(15.2)因抛出异常而终止时,或
- 当静态或线程存储持续时间(3.6.2)的非局部变量的初始化通过异常退出时,或
- 当具有静态或线程存储持续时间的对象的销毁通过异常(3.6.3)或
退出时- 执行注册
退出std::atexit
或std::at_quick_exit
的功能时,通过例外(18.5)或- 当没有操作数的 throw-expression (5.17)尝试重新抛出异常并且没有处理异常时(15.1),或
- 当
std::unexpected
通过先前违反的异常规范不允许的类型的异常退出时, std :: bad_exception未包含在该异常规范中 (15.5.2)或- 调用实现的默认意外异常处理程序(D.8.1)或
时- 为没有捕获异常的对象调用函数
std::nested_exception::rethrow_nested
(18.8.6)或- 当执行线程的初始函数时,通过异常(30.3.1.2)或
退出- 在类型
std::thread
引用可连接线程的对象上调用析构函数或复制赋值运算符时 (30.3.1.3,30.3.1.4)或- 当条件变量(30.5.1,30.5.2)上的
wait()
,wait_until()
或wait_for()
函数调用无法满足时 后置条件。 - 结束记录]在这种情况下,调用
std::terminate()
(18.8.3)。 在这种情况下 在没有找到匹配处理程序的地方,它是实现定义的 堆栈是否在std::terminate()
之前展开 叫。在搜索处理程序的情况下(15.3) 遇到一个函数的最外面的块 noexcept-specification ,它不允许异常(15.4),它是实现定义的,是否堆栈是展开的,展开的 在std::terminate()
被调用之前,部分或根本没有解开。 在所有其他情况下,堆栈不得在之前解开 调用std::terminate()
。不允许实施 完成堆栈基于确定的过早退绕 展开过程最终会调用std::terminate()
。