2013-12-15 2 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 (2) мы получаем исключение (предполагая, что вызов не вызывается в malloc, а в функцию, которая может фактически выполняться, поскольку я считаю, что концепция, которую Бьярн пытается объяснить, заключается в использовании окончательной конструкции и вызов malloc здесь неактуальен и случайен и может быть заменен любым вызовом), то если два броска, то 3 никогда не будут достигнуты, и у нас есть ресурс лука-порея от 1. Я прав?

+1

Если функция, которая действует как таНос генерирует исключение, но перед этим выделяет некоторый объем памяти это не то бесплатно, то это очень очень непослушный. Зачем предполагать такое? Никто не здравомыслящий напишет это, имо. Если бы оно выбрало исключение, никто бы не узнал адрес памяти, которую вам нужно было бы освободить. – polkadotcadaver

+0

Игнорируя, что, хотя в общих чертах, если есть исключение, возникает между распределением памяти и созданием «окончательного» объекта, то да, будет утечка. – 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++ new и C таНос. Ни один из указателей не управляется, и если какой-либо код в этот момент должен был быть выброшен, тогда будет утечка памяти. Тем не менее, обратите внимание, что 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"; 
         } 
       ); 

Однако Бьярне комментарий пятно, просто использовать std::unique_ptr.

EDIT:

Применение в конце концов:

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

Привет, я имел в виду, что если malloc был заменен каким-то другим вызовом (который потенциально мог бы выбросить), тогда произойдет утечка. – smallB

+0

Последний фрагмент кода в моих ответах охватывает это. Если есть функция, которая может перемещаться между точкой выделения и обработчиком 'finally', тогда код может протекать. Именно поэтому лучше всего использовать интеллектуальный указатель со стороны. – 111111

+0

Что в основном означает, что техника, описанная Bjarne, работает только в том случае, если отсутствует строка кода, а первая, прежде чем, наконец, вызовет броски. Должен сказать немного бессмысленно. – smallB

Смежные вопросы