LINUX.ORG.RU

Деструкторы не нужны (?)

 


0

5

Тут в соседней теме один анон сказанул следующее:

Дело не в том. Сишка, она про написание руками + можно навесит абстракций, аки глиб/гобджект. Кресты же — изначально нагромождение абстракций со строками, срущими в кучу, функциональными объектами, методами, вызывающимися неявно (например, деструкторы, на которые жаловался кармак) и проч

Собственно, хотелось бы поговорить о выделенном.

Антон прикрылся ссылкой, по которой про деструкторы я так ничего и не нашёл. Более того, в твиттере Кармака всё выглядит с точностью до наоборот — https://twitter.com/id_aa_carmack/status/172340532419375104

RAII constructor / destructor pairing and templates for type safe collections are pretty high on my list of C++ benefits over C

Кто прав? Кто виноват? И нужны ли в итоге C++ деструкторы?

Ответ на: комментарий от anonymous

Пока на аргумент не тянет.

Ну вот мы и пришли к вкусовщине. Вы не хотите знать, что bad_alloc-а было два. А мне это важно.

eao197 ★★★★★
()
Ответ на: комментарий от dzidzitop

как его написать на плюсах? буду рад увидеть элегантное решение.

Зависит от конкретной задачи. Например, исключение можно просто сохранить:

#include <exception>
#include <iostream>
using namespace std;

struct imbad {
    ~imbad() {
        try {
            throw "Ops";
        }
        catch(...) {
            e_ = current_exception();
        }
    }
    
    exception_ptr& e_;
};

int main() {
    exception_ptr e;
    imbad { e };
    
    if( e ) {
        cout << "Good bye\n";
        rethrow_exception( e );
    }
}
anonymous
()
Ответ на: комментарий от eao197

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

Именно поэтому надёжного RAII на деструкторах не построишь :-) Зачем было пиарить эту идиому тогда, не понятно :-)

Допустим, кому-то в голову придет идея, внутри деструкторов изменить подход к обработке исключений. Например, если в точке (1) возникает исключение, то информация о нем будет сохранена в каком-то списке, а работа будет продолжена дальше со следующей точки (т.е. с точки (2)).

Не допустим, а так все и делают :-) Стандартная идиома: try { // ko-ko-ko } catch (... ) {} в любом деструкторе :-)

И что, языком с таким дизайном будет пользоваться проще?

Кому как :-)

anonymous
()
Ответ на: комментарий от eao197

Вы пытаетесь своим бредом уйти от вопроса про критерии надежности?

Ты уже 2 раза упомянул о предсказуемости :-) Но это не про деструкторы в C++ :-)

anonymous
()
Ответ на: комментарий от eao197

К вашему ответу сейчас можно применить ваши же аргументы в духе «напишут непонятно как, а потом винят язык».

anonymous
()
Ответ на: комментарий от anonymous

Именно поэтому надёжного RAII на деструкторах не построишь

Пока критерии надежности не озвучены, разговаривать не о чем.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Ну вот мы и пришли к вкусовщине. Вы не хотите знать, что bad_alloc-а было два. А мне это важно.

Для bad_alloc'а можно завести счетчик=)

А если серьезно, то странно слышать подобное от человека, который защищает подход, при котором теряется вообще вся информация(или ее нужно доставать способами, сильно отличающимися от обработки ошибок в других частях языка).

anonymous
()
Ответ на: комментарий от anonymous

А развернуть мысль сможете?

Сейчас в деструкторах исключения бросать не принято, поэтому показанный выше код вполне себе легален.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

который защищает подход, при котором теряется вообще вся информация

Не то, чтобы защищаю, сколько пытаюсь показать, что озвучиваемые альтернативы, как минимум, недостаточно продуманы. И так же содержат изъяны. В том числе и с точки зрения вкусовщины.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Допустим, в точке (1) вылетает исключение. Это означает, что деструктор A прервет свою работу и действия в точках (2) и (3) не будут выполнены. А значит в списках L1, L2 и L3 останется ссылка на мусор, т.к. объекта A уже не существует.

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

anonymous
()
Ответ на: комментарий от eao197

Допустим, кому-то в голову придет идея, внутри деструкторов изменить подход к обработке исключений. Например, если в точке (1) возникает исключение, то информация о нем будет сохранена в каком-то списке, а работа будет продолжена дальше со следующей точки (т.е. с точки (2)).

Ведь эта функция будет вести себя по разному: если ее вызвали внутри ~A, то исключение не будет прерывать ее работу. А если вне ~A, то будет.

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

anonymous
()
Ответ на: комментарий от anonymous

Вы сейчас ничего путного не сказали.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

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

Деструктор — это последовательность действий, которая должна быть выполнена:

A::~A() {
  step1();
  step2();
  step3();
  ...
  stepN();
}
Допустим, на step_i у нас выскакивает исключение. Но еще остаются [step_i+1,stepN], которые нужно выполнить. Значит, мы продолжаем со step_i+1.

Теперь предположим, что все эти step1..stepN — это все внутри некоторой функции some_func.

Если эта some_func вызывается внутри A::~A() и на step_i возникает исключение, то мы не прерываем some_func, а выполняем [step_i+1,stepN].

Если же эта some_func вызывается вне A::~A() и на step_i возникает исключение, то мы прерываем some_func и не выполняем [step_i+1,stepN].

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Деструктор — это последовательность действий, которая должна быть выполнена

Это можно сказать вообще о любой программе. По крайней мере в императивном мире.

anonymous
()
Ответ на: комментарий от eao197

Допустим, на step_i у нас выскакивает исключение. Но еще остаются [step_i+1,stepN], которые нужно выполнить. Значит, мы продолжаем со step_i+1.

Это должен решить программист. Как и в случае любого другого метода. Т.е. мы прерываем some_func вне зависимости от того, откуда мы ее дернули.

И да, такая ситуация может произойти в C++ и сейчас. Ведь вам вполне может потребоваться в деструкторе сделать вещи, которые потенциально могут кидать исключения.

anonymous
()
Ответ на: комментарий от anonymous

Ведь вам вполне может потребоваться в деструкторе сделать вещи, которые потенциально могут кидать исключения.

И т.к. исключения из деструкторов выбрасывать не принято, такие действия должны требовать повышенного внимания. То бишь подавления. Что и выполняется в 99.9% случаев.

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

eao197 ★★★★★
()
Ответ на: комментарий от eao197

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

Повышенное внимание != подавление.

Фактически сейчас C++ предлагает топор, как средство от головной боли.

anonymous
()
Ответ на: комментарий от eao197

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

Недовольство вызывает не факт необходимости повышенного внимания, а факт того, что ничего кроме подавления сделать нельзя(крайне не рекомендуется).

anonymous
()
Ответ на: комментарий от anonymous

Недовольство вызывает не факт необходимости повышенного внимания, а факт того, что ничего кроме подавления сделать нельзя(крайне не рекомендуется).

Можно :-) Просто не пиши на крестах и все дела :-)

anonymous
()
Ответ на: комментарий от anonymous

Фактически сейчас C++ предлагает топор, как средство от головной боли.

А какие есть варианты? Взять ту же Java - finalize промолчит, а try-with-resources тихо и незаметно отрежет ногу подавит второе исключение.

anonymous
()
Ответ на: комментарий от anonymous

Фактически сейчас C++ предлагает топор, как средство от головной боли.

Ну остается только повторить, что в C++ это объясняется тем, как он работает. Альтернатив никто предложить не может. А существующий вариант тех, кто плотно работает с C++, устраивает более чем вполне.

Посему, если приходится пользоваться C++, то нужно жить с тем, что есть, смотреть на эти вещи трезво и не верить в чепуху от продавцов волшебных пилюль.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Альтернатив никто предложить не может.

Вы пока против цепочки исключений не предложили аргументы. Вернее предложили, но на них ответили.

А существующий вариант тех, кто плотно работает с C++, устраивает более чем вполне.

Слишком смелое утверждение.

anonymous
()
Ответ на: комментарий от anonymous

Можно :-) Просто не пиши на крестах и все дела :-)

Я и в C++ могу все руками делать, как приходится в других языках.

anonymous
()
Ответ на: комментарий от anonymous

Вернее предложили, но на них ответили.

Ну вот я пользователь языка и меня не устраивает вариант с потерей одного из bad_alloc-ов. И?

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

Я и в C++ могу все руками делать, как приходится в других языках.

Ну вот и вывод - деструкторы не нужны :-) Тему можно закрывать :-)

anonymous
()
Ответ на: комментарий от anonymous

Взять ту же Java - finalize промолчит, а try-with-resources тихо и незаметно отрежет ногу подавит второе исключение.

Но информацию о нем можно будет достать.

anonymous
()
Ответ на: комментарий от eao197

Ну вот я пользователь языка и меня не устраивает вариант с потерей одного из bad_alloc-ов. И?

Так вы и сейчас его теряете.

anonymous
()
Ответ на: комментарий от anonymous

Не так. Сейчас в принципе нет второго bad_alloc-а. Как и любого другого исключения. Либо одно единственное, либо std::terminate. Все просто.

Если вместо этого предлагается более сложный механизм с цепочкой, из которой информация может выбрасываться, то зачем этот более сложный механизм вообще?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Не так. Сейчас в принципе нет второго bad_alloc-а.

Он есть. Вы просто давите его в деструкторе.

anonymous
()
Ответ на: комментарий от anonymous

Но информацию о нем можно будет достать.

В С++ тоже можно сохранять исключения в сторону. Может парировать, что так почти никто не делает, но ведь та же ситуация и в Java.

anonymous
()
Ответ на: комментарий от eao197

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

i36_zubov
()
Ответ на: комментарий от anonymous

В С++ тоже можно сохранять исключения в сторону. Может парировать, что так почти никто не делает, но ведь та же ситуация и в Java.

Не та же. В Java это будет сделано автоматически.

anonymous
()
Ответ на: комментарий от i36_zubov

зачем вы кормите троллей?

Я думал, что здесь только тролли. Но, видимо, еще и клинические идиоты подтянулись. Пора завязывать.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

Не та же. В Java это будет сделано автоматически.

Сделано - да, проверено и обработано - нет. Результат на выходе аналогичный.

anonymous
()
Ответ на: комментарий от i36_zubov

зачем вы кормите троллей?

Почему сразу трооллей? У вас есть конструктивные аргументы против цепочки исключений? Неужели это хуже, чем подавление ошибок в деструкторах?

anonymous
()
Ответ на: комментарий от eao197

клинические идиоты

Аргументация на высоте. Очень жаль, что конструктивной критики о цепочке так и не было.

anonymous
()
Ответ на: комментарий от anonymous

Очень жаль, что конструктивной критики о цепочке так и не было.

Так вы же не хотите аргументы противоположной стороны воспринимать.

Ну и, если вас в C++ что-то не устраивает, у вас всегда есть возможность сделать лучше. Например, LLVM в руки и вперед.

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

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

Неужели это хуже, чем подавление ошибок в деструкторах?

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

Попробуйте, ради интереса, прикинуть, как будет выглядеть удаление нескольких объектов из парочки согласованных контейнеров (а-ля Boost.MultiIndex), если выброс исключения из деструктора — это нормально.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

Причём тут я

При том, что единственный ресурс, который может захватывать и освобождать твой Transzaction это refcounter соединения к базе.

Считать транзакцию ресурсом, а тем более COMMIT, where all the hard work starts, освобождением ресурса мог только обколотый скобками лишпер.

Я всего лишь показал, что в цепепе так не сделаешь

Потому что так делать и не нужно.

Всего то продемонстрировал

Не продемонстрировал.

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

Кто тебе такую чушь сказал? Что, деструктор с оператором throw в теле не компилируется?

anonymous
()
Ответ на: комментарий от monk

Никаких проблем не будет, до тех пор, пока исключение не покинет деструктор.Иначе говоря, лови в деструкторе исключение и пиши в лог об этом.

файл не смог закрыться.

как такое может быть?

anonymous
()
Ответ на: комментарий от eao197

Так вы же не хотите аргументы противоположной стороны воспринимать.

Вы ничего не возразили по поводу того, что bad_alloc является специальным случаем, если памяти действительно нет даже под очередной объект-исключение. bad_alloc итак особым случаем является.

Ну и, если вас в C++ что-то не устраивает, у вас всегда есть возможность сделать лучше. Например, LLVM в руки и вперед.

Отличный аргумент.

anonymous
()
Ответ на: комментарий от anonymous

Кто тебе такую чушь сказал? Что, деструктор с оператором throw в теле не компилируется?

Это говорит 11 стандарт. По умолчанию деструкторы noexcept. Компилироваться будет. Но упадет.

anonymous
()
Ответ на: комментарий от anonymous

Вы ничего не возразили по поводу того, что bad_alloc является специальным случаем

А что тут возражать. Это ваше частное мнение по этому поводу. Я его не разделяю.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

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

Давайте разовьем эту тему. Тут есть почва для конструктивного обсуждения.

Попробуйте, ради интереса, прикинуть, как будет выглядеть удаление нескольких объектов из парочки согласованных контейнеров (а-ля Boost.MultiIndex), если выброс исключения из деструктора — это нормально.

Может быть вы напишете более простой пример? У Multiindex'а очень укуренный код(даже IDE не все справляются), тяжело смотреть.

anonymous
()
Ответ на: комментарий от anonymous

меня больше интересует как потом гарантированно проверить этот сохранённый эксэпшин, код ошибки итд, если вне деструктора летит эксэпшин, или не летит, и когда деструкторов таких несколько.

я вижу в этом случае большой кусок спагетти-кода.

dzidzitop ★★
()
Ответ на: комментарий от anonymous

я вообще не рассматриваю бред обжабаных. тем более такой люто тупой бред.

живут себе люди, пишут на С++, и всё работает. компьютеры

внезапно прибегают программисты на жабе, и начинают требовать garbage collection, и исключения в деструкторе. им вежливо указывают на выход, намекая, что здесь на жаба. вместо того, чтоб уйти в своё болото, панки достают из шаровар говно и начинают им обмазываться, вопя «а как ты обработаешь то, что я его съем». им вежливо суют в морду швабру и говорят, что у нас так не принято. но обжабанные не унимаются и вопят «а что если я обмажусь, как обработаешь?»

в идеале, надо выгнять людей на улицу и сдать только непонятно кому - то ли полиции, то ли медикам, то ли ассенизаторам, то ли депортировать кое куда. Там пусть сами себя «обрабатывают в деструкторах».

i36_zubov
()
Ответ на: комментарий от anonymous

Деструктор с noexcept(false) не компилируется?

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.