Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
If no matching handler is found, the function std::terminate() is called; whether or not the stack is
unwound before this call to std::terminate() is implementation-defined (15.5.1).
Например если в конструкторе LockNet перед new Network будет получение какого либо хендла который надо закрыть в деструкторе — то оппа можно получить системный лок ресурса.Верно, получение хендла в конструкторе — это известная проблема, и элегантного решения, по большому счету, нет. Особенно если хендл получаешь от сторонней библиотеки, которая не бросает исключений, или это вообще системный вызов; тривиальный пример:
open(2).class LockNet{
public:
LockNet(const Url &url){
m_net1 = new Network(url);
m_net2 = new Network(url);
}
~LockNet (){
delete m_net1;
delete m_net2;
}
private:
Network *m_net1;
Network *m_net2;
};
Любой ресурс, выделяемый по new, должен оборачиваться отдельным локальным объектом.
Во-вторых, усложнять там нечего: в моём примере и так хранятся два объекта.
class LockNet{
public:
LockNet(const Url &url){
m_net = new Network(url);
}
~LockNet (){
delete m_net;
}
operator Network * (){
return network;
}
private:
Network *m_net;
};
class LockNet{
public:
LockNet(const Url &url){
m_net1 = new Network(url);
m_net2 = new Network(url);
}
~LockNet (){
delete m_net1;
delete m_net2;
}
private:
Network *m_net1;
Network *m_net2;
};
В противном случае вы не сможете отделить мусор в значении указателей от реального указателя, когда будете делать delete в catch-блоке. Собственно, по большому счету, мой «наезд» заключался именно в этом.
какой какашный код у конструктора класса LockNet. Что будет если new Network бросит исключение?
int main()
{
try
{
vector<shared_ptr<Slot>> vec {make_shared<Slot>("0"), make_shared<Slot>("1"), make_shared<Slot>("2"), make_shared<Slot>("3"), make_shared<Slot>("4")};
for (auto& x:vec)
testShared(x);
}
catch(const std::exception& e)
{
std::cerr<<e.what()<<std::endl;
}
catch(...)
{
std::cerr<<"Unknown exception"<<std::endl;
}
return 0;
}
int main() try
{
vector<shared_ptr<Slot>> vec {
make_shared<Slot>("0"),
make_shared<Slot>("1"),
make_shared<Slot>("2"),
make_shared<Slot>("3"),
make_shared<Slot>("4")};
for (auto& x:vec)
testShared(x);
return 0;
}
catch(const std::exception& e)
{
std::cerr << e.what() << std::endl;
return 1;
}
catch(...)
{
std::cerr << "Unknown exception" << std::endl;
return 1;
}
И рекомендует если вам нужно гарантированное удаление локальных объектов оборачивать код в функции main блоком try — catch (...), который перехватывает любые исключения.
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <exception>
class Transaction
{
bool active;
public:
Transaction() : active(false)
{
std::cout<<"begin transaction"<<std::endl;
active=true;
}
~Transaction()
{
rollback();
}
void commit()
{
if(!active)
return;
std::cout<<"commit transaction"<<std::endl;
active=false;
}
void rollback()
{
if(!active)
return;
std::cout<<"rollback transaction"<<std::endl;
active=false;
}
};
void do_something()
{
}
int main()
{
try
{
Transaction tr;
do_something();
tr.commit();
}
catch(const std::exception& e)
{
std::cerr<<e.what()<<std::endl;
}
catch(...)
{
std::cerr<<"Unknown exception"<<std::endl;
}
return 0;
}
begin transaction commit transaction
void do_something()
{
throw std::runtime_error("processing data failed");
}
begin transaction rollback transaction processing data failed
void Transaction::rollback()
{
if(!active)
return;
throw std::runtime_error("something bad happens when we rollback transaction");
std::cout<<"rollback transaction"<<std::endl;
active=false;
}
bool do_something()
{
return false;
}
int main()
{
...
Transaction tr;
if(!do_something())
return 1;
tr.commit();
...
}
begin transaction something bad happens when we rollback transaction
void Transaction::rollback()
{
if(!active)
return;
throw std::runtime_error("something bad happens when we rollback transaction");
std::cout<<"rollback transaction"<<std::endl;
active=false;
}
void do_something()
{
throw std::runtime_error("processing data failed");
}
int main()
{
...
Transaction tr;
do_something();
tr.commit();
...
}
begin transaction
~Transaction()
{
try
{
rollback();
}
catch(...)
{
if(!std::uncaught_exception())
throw;
}
}
Если мы не находимся в процессе обработки исключения, то можем спокойно выпустить исключение из деструктора.
Если находимся, то приходится его давить.
RAII и необрабатываемые исключения