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[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.
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...
Пока на собственное сообщение не было ответов, его можно удалить.