Re[3]: C++ без эксепшенов
От: Vamp Россия  
Дата: 28.07.11 18:31
Оценка: 6 (1) -3
I>- более простой контроль на флоу?
I>- исключениефобия?
Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.
Да здравствует мыло душистое и веревка пушистая.
Re[5]: C++ без эксепшенов
От: uzhas Ниоткуда  
Дата: 28.07.11 18:45
Оценка: +2
Здравствуйте, ilnar, Вы писали:

I>признаюсь, я тоже не фанат. но готовить умею)

а я фанат
ненавижу if-ы, они увеличивают цикломатическое число и негавтивно влияют на ковередж (юнит-тестами замучаешься все decisions покрывать)
хорошо, когда if находится в классе, а не у каждого клиента этого класса
Re[6]: C++ без эксепшенов
От: MasterZiv СССР  
Дата: 28.07.11 22:16
Оценка: +1 -1
On 28.07.2011 22:45, uzhas wrote:

> а я фанат

> ненавижу if-ы, они увеличивают цикломатическое число и негавтивно влияют на
> ковередж (юнит-тестами замучаешься все decisions покрывать)
> хорошо, когда if находится в классе, а не у каждого клиента этого класса

Главное даже не if-ы, а корректность программы.

Вот протокол (сигнатура) метода:

class Complex
{
...
Complex divide( const Complex& r ) const;
...
};


Ну и что ему возвращать при таком вызове:

Complex res = Complex( 2, 3 ).divide( 0 );

?

Если что-то возвращать, программа просто тупо становится
некорректной. А если вводить "флаги успешности выполнения
операции" -- сразу становится неуклюжей и неестественной.
Posted via RSDN NNTP Server 2.1 beta
Re[5]: C++ без эксепшенов
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 29.07.11 22:44
Оценка: +2
Здравствуйте, мыщъх, Вы писали:

М>это да. на плюсах нет возможности корректно обработать исключение. скажем, функция foo выполнила кучу операций и в какой-то момент решила открыть файл bar. и тут выяснилось, что файл открыть невозможно. что делать? кидем исключение. ловим его и видим, что (допустим) юзер вытащил флешку или cd/dvd. вот было бы здорово сказать юзеру -- воткни флешку обратно и продолжить выполнние функции foo с того места, в котором было брошено исключение. но увы... это невозможно (если только не реализовать свой диспетчер исключений).


Ты говоришь о "семантике возобновления", которой действительно нет в C++. Но это не "корректная обработка исключений".
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re: C++ без эксепшенов
От: uzhas Ниоткуда  
Дата: 28.07.11 18:11
Оценка: 9 (1)
Здравствуйте, Abyx, Вы писали:

A>Какие идиомы следует использовать, если нельзя использовать исключения?


A>Я пока остановился на вводе метода bool init(..args...),

приемлемый подход, минусы вы и сами видите
могу посоветовать еще подход bool IsValid()
в обоих случаях надобности в методе free не вижу
Re[7]: Какие исключения кидает STL?
От: Alexey F  
Дата: 29.07.11 14:02
Оценка: 9 (1)
Здравствуйте, igna, Вы писали:

I>А пользовательским аллокатором нельзя это запретить?

А как? Даже если он не стрельнет исключением и вернёт, скажем, 0, как заставить тот же vector не пройтись по памяти в попытке инициализации значений?

I>Если можно, кидает ли STL еще какие исключения?

Кидает, но к сути вопроса это относится не будет (std::vector::at бросает std::out_of_range — метод можно просто не использовать).
Re[7]: Какие исключения кидает STL?
От: sts  
Дата: 29.07.11 14:14
Оценка: 9 (1)
Здравствуйте, igna, Вы писали:

I>Здравствуйте, sts, Вы писали:


sts>>как минимум operator new который stl использует и который по умолчанию не является пользовательской функцией может кидать исключение


I>А пользовательским аллокатором нельзя это запретить? Если можно, кидает ли STL еще какие исключения? То есть, действительно ли "Без иключений нельзя использовать STL".


а как сообщать об ошибках, что памяти нет ?
все равно интерфейс stl рассчитан на исключения.
иначе придется все время какой--нибудь свой собственный errno проверять.
тогда уж проще исполльзовать c-style контейнеры (и все остальное тоже) которые будут возвращать код ошибки.
Re[8]: Давно хотел спросить...
От: Alexey F  
Дата: 29.07.11 14:36
Оценка: 1 (1)
Здравствуйте, B0FEE664, Вы писали:

MZ>>Ну и что ему возвращать при таком вызове:

MZ>>Complex res = Complex( 2, 3 ).divide( 0 );
MZ>>?

BFE>Ну и что вы будете делать с исключением, которое можно здесь бросить ?

BFE>( Чем такое поведение принципиально будет отличатся от exit(some_code)? )
Зависит от приложения. В REPL-интерпретаторе калькулятора/ЯП достаточно распечатать "Division by zero error at bla-bla-bla..." и вернуться к циклу read-eval-print (конечно, вместо конкретных чисел — переменные).
Re[4]: C++ без эксепшенов
От: мыщъх США http://nezumi-lab.org
Дата: 28.07.11 20:14
Оценка: -1
Здравствуйте, Vamp, Вы писали:

I>>- более простой контроль на флоу?

I>>- исключениефобия?
V>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

это да. на плюсах нет возможности корректно обработать исключение. скажем, функция foo выполнила кучу операций и в какой-то момент решила открыть файл bar. и тут выяснилось, что файл открыть невозможно. что делать? кидем исключение. ловим его и видим, что (допустим) юзер вытащил флешку или cd/dvd. вот было бы здорово сказать юзеру -- воткни флешку обратно и продолжить выполнние функции foo с того места, в котором было брошено исключение. но увы... это невозможно (если только не реализовать свой диспетчер исключений).
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re: C++ без эксепшенов
От: MasterZiv СССР  
Дата: 28.07.11 22:04
Оценка: +1
On 28.07.2011 22:06, Abyx wrote:

> У такого подхода даже есть преимущество над конструкторами — в init() можно

> вызывать виртуальные методы.

Преимуществ нет. В конструкторе тоже можно вызывать виртуальные методы.
Лучше поборись за использование исключений.

>

> Однако, я не уверен что это действительно хорошее решение, может есть лучше.

Использовать исключения.

> Также мне непонятно что делать с объектами создаваемыми на стеке.

> Видимо надо дополнительно вводить еще и метод free(), чтобы сразу откатить
> состояние объекта если init() провалился.

Ничего окромя

if( doAll() != doneWell )
return;

не придумаешь. И именно с этим борятся исключения.

> Это сразу же убивает автоматический вызов деструкторов,

> к тому же иногда надо будет дополнительно вводить код для предотвращения двойной
> деинициализации.

ага, тогда давай на С сразу пиши. Нафига тебе С++ ?
Без иключений нельзя использовать STL, потому что оно их кидает.
Любая НОРМАЛЬНАЯ библиотека будет тоже на исключениях.
Так что тебе останется только С-шные либы исползовать,
и свой протокол инициализации и деструкторизации придумывать.
Posted via RSDN NNTP Server 2.1 beta
Re[4]: C++ без эксепшенов
От: MasterZiv СССР  
Дата: 28.07.11 22:11
Оценка: +1
On 28.07.2011 22:31, Vamp wrote:

> Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем

> так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все,

Ну, почти правильно думашь, и почти так оно и должно быть в ХОРОШЕЙ программе
на С++.

> что бросило исключение — проваливается в самый низ, логгируется и программа

> завершается.

Ну, если конечно нельзя восстановиться и продолжить работу.

> Если программа может продолжаться — то это не исключение, а возврат ошибки из

> функции.

Нет. Путаешь. Если прогамма может продолжить работу, выбрав и уничтожив
стек вызовов и всё, что там есть, -- это одно. А если ПОТОК ВЫПОЛНЕНИЯ программы
не может течь далее в рамках его нормальных ветвей (а других в общем и не
бывает), то это вот как раз то самое место, где кидается исключение.
В общем случае это совершенно разные вещи.

Ты всегда можешь сказать программе: "А давай-ка попробуем сделать вот это,
вдруг получится", и если не получится, то привести программу в состояние,
как будто бы ничего и не было.

> Но если объект критически важен, и его несоздание должно вызывать исключение —

> то надо вызвать исключение, я так считаю.

Правильно считаешь.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: C++ без эксепшенов
От: MasterZiv СССР  
Дата: 30.07.11 08:48
Оценка: -1
On 29.07.2011 21:24, Abyx wrote:

> MZ>Преимуществ нет. В конструкторе тоже можно вызывать виртуальные методы.

> полиморфно — нельзя.

Можно. Просто вызовится не тот метод, который ты бы хотел вызвать.
Потому что в момент работы конструктора класса C объект является
объектом класса C, а не объектом класса его наследника.

> сказано "без исключений" — значит *без исключений* .

> постарайтесь обойтись без высказываний типа "сабж не нужен".
> не знаете как решить проблему — лучше помолчите.

Так я и хочу сказать как раз, что проблема не решается.
Хочешь жить неудобно, -- живи без исключений, имей кучу веток
в программе и всё такое.
Хочешь удобно -- исключения.
Posted via RSDN NNTP Server 2.1 beta
Re: C++ без эксепшенов
От: x-code  
Дата: 30.07.11 09:15
Оценка: -1
Здравствуйте, Abyx, Вы писали:

A>Какие идиомы следует использовать, если нельзя использовать исключения?

A>Я пока остановился на вводе метода bool init(..args...),
A>который проводит инициализацию и возвращает флаг успешности инициализации.
A>В случае если init() вернул false, объект надо удалить.

Да, чем-то подобным постоянно пользуюсь. Не люблю исключения — с ними получается так, что в программе возникает как-бы еще один "скрытый", неочевидный слой выполнения. Вызываешь функцию — и нет никакой гарантии, что не вывалишься куда-нибудь в совершенно другое место. Т.е. если использовать исключения — то нужно их ВЕЗДЕ использовать, кажый чих заворачивать в try/catch, перед использованием каждой функции думать, а какие там она исключения может выбросить, и т.д. Даже при отладке ставить точки останова нужно не только на строку после функции, но и на все catch, которые могут перехватывать исключения. Короче, goto 2.0

А если не использовать исключения — нужно просто сделать, чтобы функции возвращали код возврата, и все. Ну и не забывать писать проверки, но это у меня как-то на автомате получается уже
А есть еще исключения из конструкторов — любимая тема на всяких собеседованиях. С этим у меня вообще все просто: любой объект любого класса имеет как минимум два состояния — НУЛЕВОЕ и инициализированное (рабочее). Нулевое — это состояние по умолчанию, и конструктор просто обнуляет поля класса нужным образом. Никаких исключений там не может быть в принципе И никаких ресурсов в конструкторе никогда не выделяю. Ни в коем случае не открываю в конструкторе файлы, не коннекчусь к сети, не делаю запросы к БД, не выделяю память и т.д.
Ну а дальше — функции типа Init(), Create(), Open(), Load(), Connect() и т.д. по смыслу — уже осуществляющие конкретные реальные действия по переводу объекта из нулевого состояния в рабочее.
Всегда есть функция типа Free(), она освобождает ресурсы если они не освобождены, и обнуляет переменные. Ее вызов ставлю на всякий случай в деструкторе. Когда полей много, делаю еще приватную Clear(), которая как раз тупо обнуляет все поля, и ее вызываю из конструктора и из Free().

С объектами на стеке никаких проблем нет, все это прекрасно работает и на стеке.
Re[5]: C++ без эксепшенов
От: Masterkent  
Дата: 30.07.11 10:45
Оценка: :)
мыщъх:

М>скажем, функция foo выполнила кучу операций и в какой-то момент решила открыть файл bar. и тут выяснилось, что файл открыть невозможно. что делать? кидем исключение. ловим его и видим, что (допустим) юзер вытащил флешку или cd/dvd. вот было бы здорово сказать юзеру -- воткни флешку обратно и продолжить выполнние функции foo с того места, в котором было брошено исключение. но увы... это невозможно (если только не реализовать свой диспетчер исключений).


IMHO, тут всё просто реализуется:

  Скрытый текст
#include <cstring>
#include <functional>
#include <iostream>
#include <memory>
#include <stddef.h>
#include <string>
#include <type_traits>
#include <utility>
#include <windows.h>

template <class T>
    T &&multiple_forward(typename std::remove_reference<T>::type &t)
        { return static_cast<T &&>(t); }
template <class T>
    T const &multiple_forward(typename std::remove_reference<T>::type &&t)
        { return t; }

template <class ErrorHandler, class F, class... Params>
    void trial_exec(
        ErrorHandler const &error_handler,
        F const &f,
        Params &&... params)
{
    for (;;)
        try
        {
            f(multiple_forward<Params>(params)...);
            break;
        }
        catch (...)
        {
            error_handler();
        }
}

std::string WinErrorCodeDescription(DWORD err_code)
{
    char *msg_buf = 0;

    FormatMessageA(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        0,
        err_code,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (char *)&msg_buf,
        0,
        0);

    try
    {
        std::string result = msg_buf ? msg_buf : "Not enough memory";
        LocalFree(msg_buf);
        return result;
    }
    catch (...)
    {
        LocalFree(msg_buf);
        throw;
    }
}

class OpeningFileError : public std::exception
{
public:
    OpeningFileError(DWORD err_code) :
        m_msg(std::make_shared<std::string>("Failed to open file: " + WinErrorCodeDescription(err_code)))
    {}

    virtual char const *what() const throw()
    {
        return m_msg->c_str();
    }

private:
    std::shared_ptr<std::string> m_msg;
};

class WritingFileError : public std::exception
{
public:
    WritingFileError(DWORD err_code) :
        m_msg(std::make_shared<std::string>("Failed to write file: " + WinErrorCodeDescription(err_code)))
    {}

    virtual char const *what() const throw()
    {
        return m_msg->c_str();
    }

private:
    std::shared_ptr<std::string> m_msg;
};

class OutputFile
{
public:
    OutputFile(
        char const *filename,
        std::function<void ()> const &error_handler)
    {
        trial_exec(error_handler, open_file, filename, m_handle);
    }

    ~OutputFile()
    {
        if (m_handle)
            CloseHandle(m_handle);
    }

    void write(char const *data, size_t size)
    {
        DWORD bytes_written;
        if (!WriteFile(m_handle, data, size, &bytes_written, 0))
            throw WritingFileError(GetLastError());
    }

    template <size_t size>
        void write(char const (&data)[size])
    {
        write(data, size);
    }

private:
    OutputFile(OutputFile const &);
    void operator =(OutputFile const &);

private:
    static void open_file(char const *filename, HANDLE &out_handle)
    {
        out_handle = CreateFileA(
            filename,
            GENERIC_WRITE,
            0,
            0,
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            0);
        if (out_handle == INVALID_HANDLE_VALUE)
            throw OpeningFileError(GetLastError());
    }

    HANDLE m_handle;
};

class X
{
public:
    void foo(
        char const *filename,
        std::function<void()> const &error_handler)
    {
        f();                                       // некая куча операций
        OutputFile bar(filename, error_handler);   // пытаемся открыть файл bar
        do_something_with_bar(bar, error_handler); // что-то делаем с файлом bar
    }

    void f()
    {
        std::cout << "foo operations" << std::endl;
    }

    void do_something_with_bar(
        OutputFile &file,
        std::function<void ()> const &error_handler)
    {
        trial_exec(
            error_handler,
            [&file]()
                {
                    char const *s = "something";
                    file.write(s, std::strlen(s));
                }
            );
    }
};

void file_error_handler()
{
    try
    {
        throw;
    }
    catch (OpeningFileError &err)
    {
        if (MessageBoxA(0, err.what(), "Error", MB_RETRYCANCEL | MB_ICONERROR) != IDRETRY)
            throw err;
    }
    catch (WritingFileError &err)
    {
        if (MessageBoxA(0, err.what(), "Error", MB_RETRYCANCEL | MB_ICONERROR) != IDRETRY)
            throw;
    }
}

int main()
{
    try
    {
        X().foo("test.txt", file_error_handler);
    }
    catch (OpeningFileError &)
    {}
    catch (WritingFileError &)
    {}
    catch (std::exception &e)
    {
        MessageBoxA(0, e.what(), "Error", MB_OK);
    }
}

Если в целевой директории создать директорию с именем test.txt, то попытка открыть для записи файл с таким же именем приведёт к ошибке доступа. Пользователь может либо удалить файл и попробовать продолжить выполнение X::foo, либо отметить дальнейшее выполнение X::foo. Пример собирается в MinGW g++ 4.5.2.
C++ без эксепшенов
От: Abyx Россия  
Дата: 28.07.11 18:06
Оценка:
Какие идиомы следует использовать, если нельзя использовать исключения?

Я пока остановился на вводе метода bool init(..args...),
который проводит инициализацию и возвращает флаг успешности инициализации.
В случае если init() вернул false, объект надо удалить.

class Foo : Base
{
public:
    Foo() : rawPtr(NULL) {} 

    bool init()
    {
       if (!Base::init("some arg"))
          return false;

       if (!mem1.init())
          return g_log.write("Foo::init : can't init mem1"), false;

       mem2.reset(CreateSome());
       if (!mem2)
          return g_log.write("Foo::init : can't create mem2"), false;

       rawPtr = CreateBar();
       if (rawPtr == NULL)
          return false;

       return true;
    }

    ~Foo()
    {
        if (rawPtr == NULL)
           FreeBar(rawPtr);
    }

private:
    SomeDefaultConstructible mem1;
    smart_handle mem2;
    Bar* rawPtr;
};

template<class C>
inline C* create()
{
    if (C* obj = new(std::nothrow) C())
    {
        if (obj->init())
        {
            return obj;
        }
        delete obj;
    }
    return NULL;
}


У такого подхода даже есть преимущество над конструкторами — в init() можно вызывать виртуальные методы.

Однако, я не уверен что это действительно хорошее решение, может есть лучше.

Также мне непонятно что делать с объектами создаваемыми на стеке.
Видимо надо дополнительно вводить еще и метод free(), чтобы сразу откатить состояние объекта если init() провалился.
Это сразу же убивает автоматический вызов деструкторов,
к тому же иногда надо будет дополнительно вводить код для предотвращения двойной деинициализации.
In Zen We Trust
Re: C++ без эксепшенов
От: Vamp Россия  
Дата: 28.07.11 18:16
Оценка:
A>Видимо надо дополнительно вводить еще и метод free(), чтобы сразу откатить состояние объекта если init() провалился.
A>Это сразу же убивает автоматический вызов деструкторов,
Непонятно, зачем — вполне достаточно проверять флаг в самом деструкторе. А почему, если не секрет, исключения исключены (пардон за тавтологию)?
Да здравствует мыло душистое и веревка пушистая.
Re[2]: C++ без эксепшенов
От: Abyx Россия  
Дата: 28.07.11 18:19
Оценка:
Здравствуйте, uzhas, Вы писали:

U>в обоих случаях надобности в методе free не вижу


а ведь действительно, если объект создается на стеке, в случае провала init() можно сразу же сделать return и он удалится

что-то не представляю где может потребоваться вызов free()
In Zen We Trust
Re[2]: C++ без эксепшенов
От: ilnar Россия  
Дата: 28.07.11 18:28
Оценка:
Здравствуйте, Vamp, Вы писали:

A>>Видимо надо дополнительно вводить еще и метод free(), чтобы сразу откатить состояние объекта если init() провалился.

A>>Это сразу же убивает автоматический вызов деструкторов,
V>Непонятно, зачем — вполне достаточно проверять флаг в самом деструкторе. А почему, если не секрет, исключения исключены (пардон за тавтологию)?

дай угадаю:
— более простой контроль на флоу?
— исключениефобия?
— эмбеддед система, но по сути тоже исключениефобия (см. technical report on c++ performance).
— не поддерживает компилятор?
Re[2]: C++ без эксепшенов
От: Abyx Россия  
Дата: 28.07.11 18:34
Оценка:
Здравствуйте, Vamp, Вы писали:

A>>Видимо надо дополнительно вводить еще и метод free(), чтобы сразу откатить состояние объекта если init() провалился.

A>>Это сразу же убивает автоматический вызов деструкторов,
V>Непонятно, зачем — вполне достаточно проверять флаг в самом деструкторе.

имелся ввиду код типа

Foo foo;
if (!foo.init())
{
   foo.free();
   MessageBox("Foo::init failed");
   return;
}

foo.use();


но как выяснили такой код всегда можно преобразовать к виду

Foo foo;
if (!foo.init()) return;



V>А почему, если не секрет, исключения исключены (пардон за тавтологию)?

потому что проект собирается с -fno-exceptions
наверное потому что проект для embedded, а исключения вроде как раздувают бинарник (таблицами)
на самом деле я не знаю, просто такое требование %)

Вот в llvm например тоже запрещены исключения, потому что ллвм это библиотека, и разработчики не хотят чтобы использование ллвм мешало компилить код с -fno-exceptions, потому что "you only pay for what you use". Так что разные могут быть причины.
In Zen We Trust
Re[4]: C++ без эксепшенов
От: ilnar Россия  
Дата: 28.07.11 18:41
Оценка:
Здравствуйте, Vamp, Вы писали:

I>>- более простой контроль на флоу?

I>>- исключениефобия?
V>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

признаюсь, я тоже не фанат. но готовить умею)
Re[4]: C++ без эксепшенов
От: Abyx Россия  
Дата: 28.07.11 18:45
Оценка:
Здравствуйте, Vamp, Вы писали:

I>>- более простой контроль на флоу?

I>>- исключениефобия?
V>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

исключения нужны для возврата ошибки из конструктора
struct Foo
{
   Foo()
    : bar() // may throw
    , baz() // may throw
   {}

   Bar bar;
   Baz baz; 
};


и для возврата ошибки из функции которая иначе не может вернуть ошибку
int x = lexical_cast<int>("...");


в обоих случая варианты без исключений существенно снижают читаемость и надежность кода — исключения приходится заменять на член класса (isValid, whatHappened) или глобальную thread-local переменную.
In Zen We Trust
Re[5]: C++ без эксепшенов
От: ilnar Россия  
Дата: 28.07.11 19:00
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, Vamp, Вы писали:


I>>>- более простой контроль на флоу?

I>>>- исключениефобия?
V>>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

A>исключения нужны для возврата ошибки из конструктора

Vamp просто не фанат, но "с творчеством знаком", будь уверен
Re[5]: C++ без эксепшенов
От: Vamp Россия  
Дата: 28.07.11 19:00
Оценка:
A>исключения нужны для возврата ошибки из конструктора
Дело не в этом. Дело в том, что ты делаешь потом.
Да здравствует мыло душистое и веревка пушистая.
Re[5]: C++ без эксепшенов
От: ilnar Россия  
Дата: 28.07.11 19:01
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, Vamp, Вы писали:


I>>>- более простой контроль на флоу?

I>>>- исключениефобия?
V>>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

A>исключения нужны для возврата ошибки из конструктора

овпрос был в другом, почему не хотите исключений?
Re[5]: C++ без эксепшенов
От: Arsenicum Россия  
Дата: 29.07.11 07:53
Оценка:
Здравствуйте, мыщъх, Вы писали:

М>Здравствуйте, Vamp, Вы писали:


I>>>- более простой контроль на флоу?

I>>>- исключениефобия?
V>>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

М>это да. на плюсах нет возможности корректно обработать исключение. скажем, функция foo выполнила кучу операций и в какой-то момент решила открыть файл bar. и тут выяснилось, что файл открыть невозможно. что делать? кидем исключение. ловим его и видим, что (допустим) юзер вытащил флешку или cd/dvd. вот было бы здорово сказать юзеру -- воткни флешку обратно и продолжить выполнние функции foo с того места, в котором было брошено исключение. но увы... это невозможно (если только не реализовать свой диспетчер исключений).


Например можно сделать без всяких диспетчеров так:
enum Stage
{
  Start,
  Step1,
  Step2,
  Step3,
  Finish
};

struct stage_error: std::runtime_error
{
  stage_error(const std::string &message, Stage stage):
    std::runtime_error(message),
    last_stage(stage)
  { }

  Stage last_stage;
}

void foo(..., Stage current = Start)
{
  // на основе значение current выполняем определённые действия и меняем current на значение следующей стадии
  // ...

  // в текущей стадии ошибка!
  throw stage_error("ошибка", current);

  // ...
}

// здесь мы вызываем обработку
{
  try
  {
    foo(...);
  }
  catch (const stage_error &ex)
  {
     // выводим сообщение об ошибке
     // ...(ex.what())

     // просим пользователя одуматься :)

     // вызываем обработку с того самого места
     foo(..., ex.last_stage);
  }
}

Я это написал не для того чтобы поучаствовать в споре "исключения vs коды возврата", а для того чтобы показать что такую задачу можно решить с помощью исключений. Более того, я хочу сказать что в данном конкретном случае механизм обработки ошибок не существенен. В любом случае функция foo должна уметь возобновлять свою работу с определённого места и без венсения изменений в функцию foo решить такую задачу невозможно.
Re[7]: C++ без эксепшенов
От: sts  
Дата: 29.07.11 11:33
Оценка:
ООП на гольном С:
любая функция возвращает код ошибки, а первым параметром принимает this — указатель на структуру.
И получается что-то типа такого:


#define CHECK(x) \
  do {\
    int retcode = (x);\
    if (retcode != OK)\
      return retcode;\
  } while(0)

typedef struct {
    int value;
} my_class;
int my_class_init(my_class* this, int value) {
    this->value = value;
    return OK;
}
int my_class_serialize(my_class* this, char* str, size_t size) {
    if ( snprintf(....
    ...
}

int foo(char* str, size_t size) {
    my_class my_class_inst;
    CHECK(my_class_init(&my_class_inst, 10));
    CHECK(my_class_serialize(&my_class_inst, str, size));
    return OK;
}


только вот RAII нет — нужно по идее собирать списки деинициализации и в CHECK чистить все это дело
в общем, закат солнца вручную.
не знаю кому это сегодня нужно
кроме стрых проектов, написанных так для совместимости с разными страшными компиляторами

Здравствуйте, MasterZiv, Вы писали:

MZ>On 28.07.2011 22:45, uzhas wrote:


>> а я фанат

>> ненавижу if-ы, они увеличивают цикломатическое число и негавтивно влияют на
>> ковередж (юнит-тестами замучаешься все decisions покрывать)
>> хорошо, когда if находится в классе, а не у каждого клиента этого класса

MZ>Главное даже не if-ы, а корректность программы.


MZ>Вот протокол (сигнатура) метода:


MZ>class Complex

MZ>{
MZ> ...
MZ> Complex divide( const Complex& r ) const;
MZ> ...
MZ>};


MZ>Ну и что ему возвращать при таком вызове:


MZ>Complex res = Complex( 2, 3 ).divide( 0 );


MZ>?


MZ>Если что-то возвращать, программа просто тупо становится

MZ>некорректной. А если вводить "флаги успешности выполнения
MZ>операции" -- сразу становится неуклюжей и неестественной.
Re[2]: Какие исключения кидает STL?
От: igna Россия  
Дата: 29.07.11 13:03
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Без иключений нельзя использовать STL, потому что оно их кидает.


Какие исключения кидает STL?

(Именно STL, а не Standard Library; и именно сама STL, а не пользовательские функции, вызываемые из STL.)
Re[3]: Какие исключения кидает STL?
От: sts  
Дата: 29.07.11 13:07
Оценка:
Здравствуйте, igna, Вы писали:

I>Здравствуйте, MasterZiv, Вы писали:


MZ>>Без иключений нельзя использовать STL, потому что оно их кидает.


I>Какие исключения кидает STL?


I>(Именно STL, а не Standard Library; и именно сама STL, а не пользовательские функции, вызываемые из STL.)


Вот уж придрался так придрался
Re[4]: Какие исключения кидает STL?
От: igna Россия  
Дата: 29.07.11 13:24
Оценка:
Здравствуйте, sts, Вы писали:

sts>Вот уж придрался так придрался


А я не придрался, я спросил.
Re[5]: Какие исключения кидает STL?
От: sts  
Дата: 29.07.11 13:35
Оценка:
Здравствуйте, igna, Вы писали:

I>Здравствуйте, sts, Вы писали:


sts>>Вот уж придрался так придрался


I>А я не придрался, я спросил.


как минимум operator new который stl использует и который по умолчанию не является пользовательской функцией может кидать исключение
Re[6]: Какие исключения кидает STL?
От: igna Россия  
Дата: 29.07.11 13:48
Оценка:
Здравствуйте, sts, Вы писали:

sts>как минимум operator new который stl использует и который по умолчанию не является пользовательской функцией может кидать исключение


А пользовательским аллокатором нельзя это запретить? Если можно, кидает ли STL еще какие исключения? То есть, действительно ли "Без иключений нельзя использовать STL".
Re[7]: Давно хотел спросить...
От: B0FEE664  
Дата: 29.07.11 14:22
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Главное даже не if-ы, а корректность программы.


MZ>Вот протокол (сигнатура) метода:


MZ>class Complex

MZ>{
MZ> ...
MZ> Complex divide( const Complex& r ) const;
MZ> ...
MZ>};

MZ>Ну и что ему возвращать при таком вызове:


MZ>Complex res = Complex( 2, 3 ).divide( 0 );


MZ>?


Ну и что вы будете делать с исключением, которое можно здесь бросить ?

( Чем такое поведение принципиально будет отличатся от exit(some_code)? )
И каждый день — без права на ошибку...
Re[3]: Какие исключения кидает STL?
От: wander  
Дата: 29.07.11 14:25
Оценка:
Здравствуйте, igna, Вы писали:

I>(Именно STL, а не Standard Library; и именно сама STL, а не пользовательские функции, вызываемые из STL.)


Конструктор std::string в GCC бросает исключение, если передать туда ноль.
Re[4]: Какие исключения кидает STL?
От: sts  
Дата: 29.07.11 14:28
Оценка:
Здравствуйте, wander, Вы писали:

W>Здравствуйте, igna, Вы писали:


I>>(Именно STL, а не Standard Library; и именно сама STL, а не пользовательские функции, вызываемые из STL.)


W>Конструктор std::string в GCC бросает исключение, если передать туда ноль.


как я понимаю, это не стандартное поведение
Re[5]: Какие исключения кидает STL?
От: sts  
Дата: 29.07.11 14:29
Оценка:
Здравствуйте, sts, Вы писали:

sts>Здравствуйте, wander, Вы писали:


W>>Здравствуйте, igna, Вы писали:


I>>>(Именно STL, а не Standard Library; и именно сама STL, а не пользовательские функции, вызываемые из STL.)


W>>Конструктор std::string в GCC бросает исключение, если передать туда ноль.


sts>как я понимаю, это не стандартное поведение

втом смысле, что не все так делают
некоторые могут падать
Re[5]: Какие исключения кидает STL?
От: wander  
Дата: 29.07.11 14:32
Оценка:
Здравствуйте, sts, Вы писали:

sts>Здравствуйте, wander, Вы писали:


W>>Здравствуйте, igna, Вы писали:


I>>>(Именно STL, а не Standard Library; и именно сама STL, а не пользовательские функции, вызываемые из STL.)


W>>Конструктор std::string в GCC бросает исключение, если передать туда ноль.


sts>как я понимаю, это не стандартное поведение


Да. Но тем не менее.

К тому же не любой код кросскомпиляторный. Есть проекты, которые живут только на MSVC или GCC и используют их языковые расширения и особенности.
Re[7]: C++ без эксепшенов
От: gegMOPO4  
Дата: 29.07.11 14:33
Оценка:
Здравствуйте, MasterZiv, Вы писали:
MZ>Ну и что ему возвращать при таком вызове:
MZ>Complex res = Complex( 2, 3 ).divide( 0 );
MZ>?
MZ>Если что-то возвращать, программа просто тупо становится
MZ>некорректной. А если вводить "флаги успешности выполнения
MZ>операции" -- сразу становится неуклюжей и неестественной.

Ну, в данном конкретном случае есть INF и NaN. А в общем же случае заводят внутренние флаги корректности/ошибки, которые необходимо проверять внутри при каждой операции (чтобы всё окончательно не развалилось). И публичный метод доступа, который пользователю нужно проверять время от времени. Пример есть в стандартной библиотеке C++ — iostreams.
Re[8]: Давно хотел спросить...
От: Abyx Россия  
Дата: 29.07.11 17:15
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Ну и что вы будете делать с исключением, которое можно здесь бросить ?


поймаю его на границе слоя, и сообщу пользователю что операция не удалась

например
— пользователь жмет на кнопку, программа пытается выполнить операцию — возникает исключение, пользователь получает уведомление что операция не удалась — пользователь может изменить входные данные \ нажать на другую кнопку

— на веб-сервис приходит запрос — ... — сервис возвращает "500 internal error" и продолжает работу

— исключение ловится в catch(any_exception) в main loop, молча выводится в лог, делается minidump. потом можно проанализировать ситуацию и пофиксить баг.
In Zen We Trust
Re[2]: C++ без эксепшенов
От: Abyx Россия  
Дата: 29.07.11 17:24
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Преимуществ нет. В конструкторе тоже можно вызывать виртуальные методы.

полиморфно — нельзя.

>> Однако, я не уверен что это действительно хорошее решение, может есть лучше.

MZ>Использовать исключения.

сказано "без исключений" — значит *без исключений* .
постарайтесь обойтись без высказываний типа "сабж не нужен".
не знаете как решить проблему — лучше помолчите.

MZ>ага, тогда давай на С сразу пиши. Нафига тебе С++ ?

MZ>Без иключений нельзя использовать STL, потому что оно их кидает.
MZ>Любая НОРМАЛЬНАЯ библиотека будет тоже на исключениях.
см. LLVM
In Zen We Trust
Re: C++ без эксепшенов - фабрики
От: Abyx Россия  
Дата: 29.07.11 20:11
Оценка:
А как насчет фабрик?

Например — статический метод create()

class Foo
{
public:
    static Foo* create(..args..)
    {
        scoped_ptr<Bar> bar(Bar::create());
        if (!bar) return;
        scoped_handle h(CreateSome(...));
        if (!h) return;
        return new(std::nothrow) Foo(bar.release(), h.release());
    }

    Foo(Bar* bar, HANDLE h) : bar(bar), h(h) {}

private:
    scoped_ptr<Bar> bar;
    scoped_handle h;
};


Преимущества
— нет отдельно висящего метода init(), create выдает гарантированно валидный настроенный объект, либо NULL
— ???

Недостатки
— чтобы создать объект на стеке, надо скопипастить всё содержимое create() кроме new
— в конструктор вытаскиваются *все* члены класса с нетривиальной инициализацией — а это нарушает инкапсуляцию
— непонятно как быть с базовым классом

Или — классическая фабрика — функция или (виртуальный) метод

class Foo
{
public:
    Foo(Bar* bar, HANDLE h) : bar(bar), h(h) {}

private:
    scoped_ptr<Bar> bar;
    scoped_handle h;
};

Foo* createFoo(...args..)
{
    scoped_ptr<Bar> bar(Bar::create());
    if (!bar) return;
    scoped_handle h(CreateSome(...));
    if (!h) return;
    return new(std::nothrow) Foo(bar.release(), h.release());
}


Преимущества — труъ ООП, dependency injection, etc
В остальном всё так же как и у статического метода
In Zen We Trust
Re[4]: C++ без эксепшенов
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 29.07.11 21:39
Оценка:
Здравствуйте, Vamp, Вы писали:

Нe только в main — на границах модулей тоже лучше преобразовывать исключения в коды ошибок — при проблемах часть функционала отвалится, но хоть остальное похромает дальше, если сможет. Более чем актуально, когда модули самые что ни на есть модульные, и создаются разными компиляторами.
Маньяк Робокряк колесит по городу
Re[8]: C++ без эксепшенов
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 29.07.11 22:00
Оценка:
Здравствуйте, gegMOPO4, Вы писали:

MOP>Ну, в данном конкретном случае есть INF и NaN. А в общем же случае заводят внутренние флаги корректности/ошибки, которые необходимо проверять внутри при каждой операции (чтобы всё окончательно не развалилось). И публичный метод доступа, который пользователю нужно проверять время от времени. Пример есть в стандартной библиотеке C++ — iostreams.


iostreams — дерьмовая вообщем-то библиотека.
Проверять корректность каждой операции в общем случае значит умножать кол-во кода в 3-10 раз, плюс ошибки на неизбежном в таком случае копипасте. Я чтою на позиции, что внутри модудей — исключения, на границах — код ошибки + доп.нформация о ней, в main — все коды ошибок опять же преобразовываются в исключения, и выводим что поймаем
Маньяк Робокряк колесит по городу
Re[5]: C++ без эксепшенов
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 29.07.11 22:07
Оценка:
Здравствуйте, Abyx, Вы писали:

A>в обоих случая варианты без исключений существенно снижают читаемость и надежность кода (1)- исключения приходится заменять на член класса (isValid, whatHappened) или глобальную thread-local переменную (2),

которые можно без проблем проигнорировать на любом уровне и получит проблемы на абсолютно другом уровне (к п2).
По п. 1 Сами по себе не снижают, либо снижается надежность игнором проверки ошибок, либо читаемость раздуванием кода в несколько раз за счет этих проверок.
Маньяк Робокряк колесит по городу
Re[3]: Какие исключения кидает STL?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 29.07.11 23:58
Оценка:
Здравствуйте, igna, Вы писали:

MZ>>Без иключений нельзя использовать STL, потому что оно их кидает.


I>Какие исключения кидает STL?


I>(Именно STL, а не Standard Library; и именно сама STL, а не пользовательские функции, вызываемые из STL.)

1) А чем отличается STL от Standard Library?
2) bad_alloc, или что там кидается при отсутствии памяти?
3) Таки да, но кто же использует кастомные аллокаторы? Это чуть ли не весь клиентский код переписывать, раз, во-вторых — как все таки возвращать ошибку аллокатора, который вызван не явно?
Придумайте std::string, который не кидает исключений, и который не надо перед каждой операцией проверять на консистентность.
Маньяк Робокряк колесит по городу
Re[8]: Давно хотел спросить...
От: MasterZiv СССР  
Дата: 30.07.11 08:35
Оценка:
On 29.07.2011 18:22, B0FEE664 wrote:

> Ну и что вы будете делать с исключением, которое можно здесь бросить ?


Ловить в main или в главном цикле обработки кусков информации, которые
программа обрабатывает. После каждой итерации.

>

> ( Чем такое поведение принципиально будет отличатся от exit(some_code)? )

Тем, что не надо В КАЖДОЙ ФУНКЦИИ обрабатывать эту сраную ошибку.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: Какие исключения кидает STL?
От: MasterZiv СССР  
Дата: 30.07.11 08:44
Оценка:
On 29.07.2011 17:03, igna wrote:

> Какие исключения кидает STL?

>
> (Именно STL, а не Standard Library; и именно сама STL, а не пользовательские
> функции, вызываемые из STL.)

Нарушения границ массива, не ?
Posted via RSDN NNTP Server 2.1 beta
Re: C++ без эксепшенов
От: Ligen Украина http://zone-of-ambiguity.blogspot.com/
Дата: 30.07.11 21:30
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Какие идиомы следует использовать, если нельзя использовать исключения?


Рекомендуется использовать RAII (как и в случае с исключениями), но таки да, придется выносить всю логику конструирования объектов из конструкторов в init'ы. Из этого следует, что нужно обязательно запрещать конструктор копирования и оператор присваивания для всех классов. Вместо bool предпочтительнее использовать коды ошибок.
Тогда типичный класс будет выглядеть вот так:

class CSmth
{
     CSmth(const CSmth & );
     CSmth & operator = (const CSmth & );
public:
     CSmth();
     ~CSmth();
     error_code Init(,,,,);

     ...
};


Можно сделать пару макросов вида:
#define CHECK(X)   {   error_code code = (X);  if (success(code)) return code; }
#define CHECK_ALLOC(X)   {   if (!(X)) return error_no_memory; }

потому что запаришься руками везде писать.

Так же рекомендуется тестировать приложение с всяческими тулзами вроде AppVerifier или Driver Verifier с опцией Low Resources Simulation, потому что все равно что нибудь да пропускаешь.

STL отпадает на 99.99%, остается лишь прекрасный std::auto_ptr и может еще что-то по мелочам.
Для хранения данных приходится пользоваться готовыми hash table'ами, r/b или avl tree из C и/или писать свои поделки/обертки.
Viva el Junta Militar! Viva el Presidente!
Re[6]: C++ без эксепшенов
От: Uzumaki Naruto Ниоткуда  
Дата: 31.07.11 08:25
Оценка:
U>а я фанат
U>ненавижу if-ы, они увеличивают цикломатическое число и негавтивно влияют на ковередж (юнит-тестами замучаешься все decisions покрывать)
U>хорошо, когда if находится в классе, а не у каждого клиента этого класса

Попробуй побыстрому свою программу, не переписывая затащить на ucLinux на какое-нибудь устройство х)

Re[3]: Какие исключения кидает STL?
От: Alexander G Украина  
Дата: 31.07.11 11:45
Оценка:
Здравствуйте, igna, Вы писали:

I>Здравствуйте, MasterZiv, Вы писали:


MZ>>Без иключений нельзя использовать STL, потому что оно их кидает.


I>Какие исключения кидает STL?


out_of_range, invalid_argument, length_error

I>(Именно STL, а не Standard Library; и именно сама STL, а не пользовательские функции, вызываемые из STL.)


Как считать, bad_alloc у аллокатора кидает пользовательская функция или нет, если аллокатор стандарный ?
Русский военный корабль идёт ко дну!
Re[2]: C++ без эксепшенов
От: MasterZiv СССР  
Дата: 01.08.11 06:35
Оценка:
On 30.07.2011 13:15, x-code wrote:

> Да, чем-то подобным постоянно пользуюсь. Не люблю исключения — с ними получается

> так, что в программе возникает как-бы еще один "скрытый", неочевидный слой
> выполнения.

Во-во, об этом я и говорил. Они этого "неочевидного слоя выполнения"
боятся как огня. Те, кто не понимает исключения и другие виды альтернативных
потоков управления.

Вызываешь функцию — и нет никакой гарантии, что не вывалишься
> куда-нибудь в совершенно другое место. Т.е. если использовать исключения — то
> нужно их ВЕЗДЕ использовать, кажый чих заворачивать в try/catch, перед
> использованием каждой функции думать, а какие там она исключения может
> выбросить, и т.д. Даже при отладке ставить точки останова нужно не только на
> строку после функции, но и на все catch, которые могут перехватывать исключения.
> Короче, goto 2.0

Ой, какое блин горе. Для сведения, ставить точку прерывания в catch бесполезно,
потому что ПОЗДНО, стек уже раскручен, к тому же почти все отладчики умеют при
выкидывании исключения ставить точки прерывания.

> А если не использовать исключения — нужно просто сделать, чтобы функции

> возвращали код возврата, и все. Ну и не забывать писать проверки, но это у меня
> как-то на автомате получается уже

Ну, поздравляю, значит у тебя стабильная привычка писать говнокодильник.

> А есть еще исключения из конструкторов — любимая тема на всяких собеседованиях.


Ну да, горе безысходное, конец света
Posted via RSDN NNTP Server 2.1 beta
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.