21

Re: C++ — чи є життя без try finally?

koala написав:
ADR написав:

Натискаєте кнопку "завантажити"
Форма блокується (чи просто LoadButton.Disable()) і відоражається прогрес бар завантаження
Завантаження
Форма розблоковується (LoadButton.Enable())
<виводиться помилка завантаження>

Створюється об'єкт "блок". При виході з функції (неважливо, якому) він знищується. Пропонуєте робити це без об'єктів?

у C++ від Microsoft і від Embercadero (CBilder) є "__finalli". Невже немає чогось такого для компілятора з набору GCC?

22

Re: C++ — чи є життя без try finally?

Тільки от y() може викинути TheirsException, тоді про MyException взагалі ніхто не дізнається. Що тоді робити?

23

Re: C++ — чи є життя без try finally?

quez написав:

Тільки от y() може викинути TheirsException, тоді про MyException взагалі ніхто не дізнається. Що тоді робити?

це проблема вищого рівня.
головне що те що було блоці фіналі було виконано.

24

Re: C++ — чи є життя без try finally?

Torbins написав:

Підтримаю ADR: у випадку, коли у C# можна записати алгоритм п'ятьма рядками коду завдяки finally, у C++ треба створювати окремий клас та об'єкт. Це однозначно ускладнює сприйняття коду, робить його громіздким не надаючи якихось суттєвих переваг.

Чому без finally, тому що є деструктори, які спрацьовують автоматом. Деструктор краще ніж finally, ви не засмічуєте код своєї логікою завершення. Наявність finally у С# викликана відсутністю деструкторів.

Подякували: leofun011

25

Re: C++ — чи є життя без try finally?

Yola написав:
Torbins написав:

Підтримаю ADR: у випадку, коли у C# можна записати алгоритм п'ятьма рядками коду завдяки finally, у C++ треба створювати окремий клас та об'єкт. Це однозначно ускладнює сприйняття коду, робить його громіздким не надаючи якихось суттєвих переваг.

Чому без finally, тому що є деструктори, які спрацьовують автоматом. Деструктор краще ніж finally, ви не засмічуєте код своєї логікою завершення. Наявність finally у С# викликана відсутністю деструкторів.

як красиво реалізувати цей код?

WorkBeginEvent(WorkCount = count);
try
  for i := to count do
  begin
    SomeWork();
    WorkEvent(i);
  end
finally
  WorkEndEvent()
end

або цей:

void f(){
  try {
    x();
  }
  finally {
    y();
  }
}
...
try{
  f();
}
catch( MyException &e) {
  Handle(e);
}

26

Re: C++ — чи є життя без try finally?

Це різні коди. Причому наведені саме для прикладу. Щоб красиво реалізувати код, треба враховувати багато деталей.

27 Востаннє редагувалося ADR (16.02.2016 18:24:05)

Re: C++ — чи є життя без try finally?

Хм. Якщо у плюсах прийнято писати блокувальники, то для цього має бути шаблон. Є таке? типу

LookTemplate look{void (void){ 
  // код деструктора
});

28

Re: C++ — чи є життя без try finally?

ADR написав:

Хм. Якщо у плюсах прийнято писати блокувальники, то для цього має бути шаблон. Є таке? типу

LookTemplate look{void (void){ 
  // код деструктора
});

У стандарті я такого не бачив. Можна написати клас, що прийматиме лямбду і виконуватиме її. Хоча передати лямбду у функцію буде нетривіально. З іншого боку можна обійтись std::function.

29 Востаннє редагувалося leofun01 (16.02.2016 20:08:06)

Re: C++ — чи є життя без try finally?

Yola написав:

Наявність finally у С# викликана відсутністю деструкторів.

https://docs.microsoft.com/uk-ua/dotnet … finalizers
Не лякайте мене так :)

І взагалі деструктори і finally мають різні призначення.

30

Re: C++ — чи є життя без try finally?

leofun01 написав:
Yola написав:

Наявність finally у С# викликана відсутністю деструкторів.

https://docs.microsoft.com/uk-ua/dotnet … finalizers
Не лякайте мене так :)

Так, але виконуються вони тоді коли заманеться збирачу сміття.

leofun01 написав:

І взагалі деструктори і finally мають різні призначення.

Ніколи не стверджував зворотнього :)

Подякували: leofun011

31 Востаннє редагувалося -=ЮрА=- (16.02.2016 21:43:48)

Re: C++ — чи є життя без try finally?

Маємо витік пам'яті:

- я спробую пожартувати, "ще Геракліт заповів - робиш поліморфний об'экт - зроби базову болванку з віртуальним деструктором, потім обвішуй методами". Це знаєте як протектед наслідування - якщо воно є - майже 100% помилка дизайну, теж саме у вашому прикладі.

32

Re: C++ — чи є життя без try finally?

-=ЮрА=- написав:

"ще Геракліт заповів - робиш поліморфний об'экт - зроби базову болванку з віртуальним деструктором, потім обвішуй методами".

А якщо хоч об'єкт і поліморфний, але поліморфне видалення не дозволено, то зроби деструктор protected і не віртуальним.

33 Востаннє редагувалося ADR (17.02.2016 01:51:07)

Re: C++ — чи є життя без try finally?

Тобто я замість такого коду:

class SampleLoader : public QObject
{
    Q_OBJECT
public:
    explicit SampleLoader(QObject *parent = 0);
    void load(QString sampleParameter);

signals:
    void workBeginEvent(int stepsCount);
    void workEvent(int step);
    void workEndEvent(bool sampleResult);

public slots:
};

void SampleLoader::load(QString sampleParameter)
{
    int count = 10;
    bool someResult = false;
    emit workBeginEvent(count);
    try 
    {
        for(int i = 0; i < count; i++)
        {
            QTest::qSleep(100); // hard work
            emit workEvent(i);
        }
        someResult = true;
    }
    finally
    {
        emit workEndEvent(someResult);
    }
}

маю писати об'єкт "runAfter" в дестрікторі писати виклик функції workEndEvent, а для цього ще потрібно додати параметри this і someResult до того об'єкта...

та ну... не може все бути так складно...

34

Re: C++ — чи є життя без try finally?

А якщо хоч об'єкт і поліморфний, але поліморфне видалення не дозволено, то зроби деструктор protected і не віртуальним.

- ні на такі речі він теж казав помилка дизайну.

35 Востаннє редагувалося -=ЮрА=- (17.02.2016 07:39:59)

Re: C++ — чи є життя без try finally?

ADR,

workBeginEvent(count);
try{}catch(...){}
workEndEvent(someResult);

#include <iostream>
#include <thread>
#include <mutex>
#include <map>
#include <string>
 
std::map<std::string, std::string> g_pages;
std::mutex g_pages_mutex;
 
void save_page(const std::string &url)
{
    std::string result = "fake content";
 
    g_pages_mutex.lock();
    try{
        g_pages[url] = result;
        if( url.find("thrd2", 0) != std::string::npos )
            throw "I'm naipnulosya";
    }
    catch(const char * msg){
         g_pages[url] = msg;
    }
    g_pages_mutex.unlock();
}
 
int main()
{
    std::thread t1(save_page, "http://thrd1URL");
    std::thread t2(save_page, "http://thrd2URL");
    t1.join();
    t2.join();
 
    g_pages_mutex.lock();  
    for (const auto &pair : g_pages) {
        std::cout << pair.first << " => " << pair.second << '\n';
    }
    g_pages_mutex.unlock();  
    return 0;
}

http://ideone.com/zlMlj2

Прихований текст

Ось скажіть - якого дідька вам там файналі взагалі потрібно? Ви багатопоточним робіть!
...завантаження у головному потоку, "Геракліт сказав що піде топитися до Стіксу..."

Подякували: ADR, leofun012

36

Re: C++ — чи є життя без try finally?

-=ЮрА=- написав:

А якщо хоч об'єкт і поліморфний, але поліморфне видалення не дозволено, то зроби деструктор protected і не віртуальним.

- ні на такі речі він теж казав помилка дизайну.

А Герб Саттер каже, що так і треба :)

І мабуть краще так,

    try{
        {
            std::lock_guard<std::mutex> lock(g_pages_mutex);
            g_pages[url] = result;
        }
        if( url.find("thrd2", 0) != std::string::npos )
            throw "I'm naipnulosya";
    }
    catch(const char * msg){
         std::lock_guard<std::mutex> lock(g_pages_mutex);
         g_pages[url] = msg;
    }

Щоб менше часу тримати мютекс і нічого поганого не сталось якщо виняткова ситуація станеться під час запису у g_pages.

Подякували: leofun011

37

Re: C++ — чи є життя без try finally?

-=ЮрА=- написав:

ADR,

workBeginEvent(count);
try{}catch(...){}
workEndEvent(someResult);

1. я не хочу давити помилки (створювати змінну в якій тичасово їх записувати?)
2. якщо в try catch буде return то workEndEvent не виконається

-=ЮрА=- написав:
#include <iostream>
#include <thread>
#include <mutex>
#include <map>
#include <string>
 
std::map<std::string, std::string> g_pages;
std::mutex g_pages_mutex;
 
void save_page(const std::string &url)
{
    std::string result = "fake content";
 
    g_pages_mutex.lock();
    try{
        g_pages[url] = result;
        if( url.find("thrd2", 0) != std::string::npos )
            throw "I'm naipnulosya";
    }
    catch(const char * msg){
         g_pages[url] = msg;
    }
    g_pages_mutex.unlock();
}
 
int main()
{
    std::thread t1(save_page, "http://thrd1URL");
    std::thread t2(save_page, "http://thrd2URL");
    t1.join();
    t2.join();
 
    g_pages_mutex.lock();  
    for (const auto &pair : g_pages) {
        std::cout << pair.first << " => " << pair.second << '\n';
    }
    g_pages_mutex.unlock();  
    return 0;
}

http://ideone.com/zlMlj2

Прихований текст

Ось скажіть - якого дідька вам там файналі взагалі потрібно? Ви багатопоточним робіть!
...завантаження у головному потоку, "Геракліт сказав що піде топитися до Стіксу..."

І куди ви мої івенти забрали? на скільки я розумію то в конструктор чи деструктор їх запхати проблемно. писати workBeginEvent біля g_pages_mutex.lock();, а workEndEvent біля g_pages_mutex.unlock(); ? але тоді знову немає гарантії що між ними не викинеться помилка.

Для спрощення можна сказати що workBeginEvent це loadButton.Disable(),  а workEndEvent це loadButton.Enable(). Куди це можна записати?

...завантаження у головному потоку

у вашому прикладі я все одно не маю гарантії що g_pages_mutex.unlock(); виконається.


а взагалі ось приклад:

маємо такий стан:
https://habrastorage.org/files/8e9/5ac/ce6/8e95acce6d624b15b82b2e5ae8569760.png

коли натискаємо кнопку Search то виконується якийсь метод (аналог load в Loader), який у свою чергу відсилає сигнал про те що він почав роботу (workBeginEvent) і переводить форму у такий стан:
https://habrastorage.org/files/4f6/5f2/672/4f65f2672ee54f64b2c75b96e5a51fd4.png

коли пошук знаходить якийсь елемент то сповіщає про це (workEvent)
https://habrastorage.org/files/d5d/1b7/1c2/d5d1b71c20124bbea5c667334b7744ed.png

також сповіщає (а це вже обов'язково!) про те що пошук завершений (workEndEvent)
https://habrastorage.org/files/f9f/f2d/e9d/f9ff2de9db744b22b1c7a392994fd960.png

це страшно глючний приклад роботи з Bluetooth Low Energy, який я хотів переписати, чи хоча б поставити костилі

38 Востаннє редагувалося -=ЮрА=- (17.02.2016 09:51:54)

Re: C++ — чи є життя без try finally?

ADR написав:

І куди ви мої івенти забрали?

- замінив їх на мьютекси (тіж івенти тільки з автосбросом), я взагалі вам синхронізацію демоснтрував, проте втикніть туди свою івенту(це на касається основної теми яку ви затронули, я навів вам приклад де ще окрім стейту батону обходимо дедлок при синхронізації при обвалі треди,а це куди критичніша помилка ніж активність елемнту гуі). Як какзав Геракліт "досить слів...", тому ось вам приклад з батонами

#include <iostream>
#include <thread>
#include <mutex>
#include <string>


std::mutex g_pages_mutex;

class cButtonEmul{
protected:
    bool bState;
public:
    cButtonEmul(bool bState = true){
        cButtonEmul::bState = bState;
    }
    bool getState(){return bState;}
    bool setState(bool bState){
        cButtonEmul::bState = bState;
    }
};

struct sThreadParam{
    std::string *url;
    cButtonEmul *btn;
};
 

void save_page(const sThreadParam &param)
{
    if( param.btn )
        param.btn->setState(false);
    g_pages_mutex.lock();
    try
    {
        try
        {
            if( param.url ){
            if( param.url->find("thrd2", 0) != std::string::npos )
                throw "I'm naipnulosya";
            else
            if( param.url->find("thrd1", 0) != std::string::npos )
                throw 0;
            else
               *param.url = "fake content";
            }
        }
        catch(const char * msg){
            if( param.url )
               *param.url = msg;
        }
    }
    catch(...){
        g_pages_mutex.unlock();
        if( param.url )
           *param.url = "unhandled exception occured!";
        if( param.btn )
            param.btn->setState(true);
        return;//àâàð³éíèé âèõ³ä
    }
    g_pages_mutex.unlock();
    if( param.btn )
        param.btn->setState(true);
}
 
int main()
{
    cButtonEmul btn1(false);std::string sDownload1 = "http://thrd1URL";
    cButtonEmul btn2(false);std::string sDownload2 = "http://thrd2URL";
    cButtonEmul btn3(false);std::string sDownload3 = "http://thrd3URL";
    sThreadParam prm1 = {&sDownload1, &btn1};
    sThreadParam prm2 = {&sDownload2, &btn2};
    sThreadParam prm3 = {&sDownload3, &btn3};
    std::thread t1(save_page, prm1);
    std::thread t2(save_page, prm2);
    std::thread t3(save_page, prm3);
    t1.join();
    t2.join();
    t3.join();
 
    g_pages_mutex.lock();  
    std::cout<< sDownload1 <<" btn1 state : "<<std::string(btn1.getState() ? "enabled" : "disabled")<<std::endl;
    std::cout<< sDownload2 <<" btn2 state : "<<std::string(btn2.getState() ? "enabled" : "disabled")<<std::endl;
    std::cout<< sDownload3 <<" btn3 state : "<<std::string(btn3.getState() ? "enabled" : "disabled")<<std::endl;
    g_pages_mutex.unlock();  
    return 0;
}

http://ideone.com/sA0aDG

unhandled exception occured! btn1 state : enabled - той трай якраз відпрацьовує щось зовсім несподіване. Як бачите ніякого файналі не потрібно.

39 Востаннє редагувалося -=ЮрА=- (17.02.2016 10:34:56)

Re: C++ — чи є життя без try finally?

Yola написав:

А Герб Саттер каже, що так і треба

- (балакав з Гераклітом, ось що він переказав : "хай той герб створить той об'єкт(з протектед деструктором) не по поінтеру, тоді поговоримо...").
http://ideone.com/KgQPnR
нижче невірний дизайн і чхати на герба ;)

Прихований текст

нижче єдиний варіант коли щось зможе відпрацювати
http://ideone.com/0YpTtS
тобто ні деліт, ні глобал, ні копія, нічого з цього працьювати не буди - ви мені скажить що це не помилка дизайну

40

Re: C++ — чи є життя без try finally?

-=ЮрА=- написав:
Yola написав:

А Герб Саттер каже, що так і треба

- (балакав з Гераклітом, ось що він переказав : "хай той герб створить той об'єкт(з протектед деструктором) не по поінтеру, тоді поговоримо...").

Не добрав :(

class I {
    virtual void method() = 0;
protected:
    ~I() {}
};
 
class A : public I {
    void method() override {}
};

void main() {
    A a;
}