2013-12-15 128 views
0

在最新的C++编程语言书中,Bjarne提出了一种正统错误处理的替代方案,即使用异常。这是章13.3.1,他写道:内存管理策略问题

void test() 
    // handle undiciplined resource acquisition 
    // demonstrate that arbitrary actions are possible 
{ 
    int* p = new int{7};        // probably should use a unique_ptr (§5.2) 
    int* buf = (int*)malloc(100*sizeof(int));   // C-style allocation 

    auto act1 = finally([&]{ delete p; 
           free(buf);    // C-style deallocation 
           cout<< "Goodby, Cruel world!\n"; 
          } 
        ); 

    int var = 0; 
    cout << "var = " << var << '\n'; 

    // nested block: 
    { 
      var = 1; 
      auto act2 = finally([&]{ cout<< "finally!\n"; var=7; }); 
      cout << "var = " << var << '\n'; 
    } // act2 is invoked here 

    cout << "var = " << var << '\n'; 
}// act1 is invoked here 

虽然我明白他试图解释,什么该代码应该实现的,我有问题,认为这片段是免费韭菜:

> 1. int* p = new int{7};        // probably should use a unique_ptr (§5.2) 
> 2.   int* buf = (int*)malloc(100*sizeof(int));   // C-style allocation 
>   
>  
> 3.   auto act1 = finally([&]{ delete p; 
>           free(buf);    // C-style deallocation 
>           cout<< "Goodby, Cruel world!\n"; 
>         } 
>        ); 

为什么? 因为如果在第二行(2)我们得到异常抛出(假设没有调用一个malloc而是一个可以实际抛出的函数,因为我相信Bjarne试图解释的概念是使用finally构造这里的malloc调用是不相关的,偶然的,可以被任何调用取代),那么如果两个抛出然后3永远不会到达,我们有资源韭菜从1 我是否正确?

+1

如果这就像一个的malloc函数抛出一个异常,但这样做之前,所以分配一些内存它不那么自由,那么它是非常很调皮。为什么要承担这样的事情?没人理智会写,imo。如果它抛出异常,没有人会知道你将不得不释放的内存地址。 – polkadotcadaver

+0

尽管如此,如果在内存分配和“finally”对象创建之间引发异常时忽略这一点,那么会出现泄漏。 – polkadotcadaver

+0

@polkadotcadaver:泄漏不会出现在* buf中,而是出现在* p中。 –

回答

1

基本上什么是在上面的代码段发生的事情是:

 int* p = new int{7};        // probably should use a unique_ptr 
    int* buf = (int*)malloc(100*sizeof(int));   // C-style allocation 

分配内存两者经由C++ newC的malloc。这两个指针都没有管理,如果此时有任何代码被抛出,内存将被泄漏。但是请注意,malloc不会如此孤立地抛出此代码是安全的。

http://en.cppreference.com/w/cpp/memory/c/malloc

auto act1 = finally([&]{ delete p; 
          free(buf);    // C-style deallocation 
          cout<< "Goodby, Cruel world!\n"; 
         } 
       ); 

在这种代码的RAII类型是从最后函数返回。当act1被销毁时(无论是例外情况还是离开此范围),它将执行可调用参数。

因为这直接跟在malloc之后我们现在已确保内存不会泄漏。

下面的代码不过是不安全的:

 int* p = new int{7};        // probably should use a unique_ptr 
    int* buf = (int*)malloc(100*sizeof(int));   // C-style allocation 

    throwing_function(); 

    auto act1 = finally([&]{ delete p; 
          free(buf);    // C-style deallocation 
          cout<< "Goodby, Cruel world!\n"; 
         } 
       ); 

但是Bjarne的评论是现货上,只需使用一个std::unique_ptr

编辑:

一种利用最后:

database_handle dh1; 
dh1.do("action..."); 
finally([&]{ 
    if(!dh1.success()) { 
     dh1.rollback(); 
    } 
); 
+0

嗨,我的意思是说,如果malloc被其他调用替换(可能会抛出),则会发生泄漏。 – smallB

+0

我的答案中的最后一段代码涵盖了这一点。如果有一个函数可以在分配点和'finally'处理函数之间传递,那么是的代码可能会泄漏。这就是为什么最好使用智能指针的原因。 – 111111

+0

这基本上意味着Bjarne解释的技术仅在没有任何代码行的情况下才起作用,但是在最后调用投掷之前的第一行代码。有点毫无意义,不得不说。 – smallB