LINUX.ORG.RU

stack.peek для пустого стека вызывает сегфолт, а в дебаг-режиме ошибку Assert

 


0

1
std::stack<MyClass2> st;

std::cout << st.top().x;

Это прикол такой, да? Зачем вводились в C++ исключения, если они не используются. Небезопасно разыменовать неправильный указатель я могу и без STL. Вопрос, а зачем мне тогда класс stack? :)


Исключения используются там, где они могут возникнуть по логике работы кода из-за внешних причин. А у тебя речь про баг в коде. Хотя я не знаю что за шаблон stack, но наверно где-то прописано что так делать нельзя. Ассерт тому подтверждение. Если ставить везде проверки - код медленнее работает.

firkax ★★★★★
()

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

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

В C++ не принято платить за то чем не пользуются

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

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

Бред

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

Почему это должно проверяться в твоём коде:

  • В своём коде ты можешь знать что стек непустой, и не делать проверки.
  • Если ты не знаешь пустой ли стек, ты можешь сделать проверку, это во-первых, будет явный и очевидный код, во-вторых быстрый, по сравнению с попыткой взять элемент и ловлей исключения.
slovazap ★★★★★
()
Ответ на: комментарий от Udacha

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

Тогда ты выбрал не тот язык. C++ выбирают как раз за то что он позволяет не платить за лишние проверки. И нет, она не микроскопическая - какой-нибудь tight loop где ты просто берёшь int из контейнера (один indirection) добавление проверки и целого бранча просадит, даже несмотря на предикшон.

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

В своём коде ты можешь знать что стек непустой, и не делать проверки.

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

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

Файл это внешний объект, его может запороть глупый юзер вне контроля твоей программы. Или может диск износиться и дать i/o error, что тоже штатная ситуация. А стек в памяти и запороть его можно только специально подключившись отладчиком.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от Udacha

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

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

А тут вообще пустой объект возвращается. Типа сегфолт не комильфо, давайте хоть что-то возвратим :)

operator[] создаёт элемент мапы при его отсутствии и возвращает ссылку на существующий/созданный элемент. Читайте cppreference хотя бы.

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

Какой идиот это кодил..

Смотри что в стандарте написано: https://eel.is/c++draft/stack#defn

reference         top()             { return c.back(); }
const_reference   top() const       { return c.back(); }

Походу идиот это ты, а не тот кто кодил. Кто кодил, тот выполнил т.з. на 100%

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

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

ассерты можно включить и для релизного режима сборки…

fsb4000 ★★★★★
()

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

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

Если для критична производительность, я вообще не выберу C++ с STL. То есть кресты это ни рыба, ни мясо.

Вы не котиков не любите, Вы их готовить не умеете.

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

Ты не понимаешь что такое исключительная ситуация и когда уместны исключения

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

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

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

kvpfs ★★
()
Последнее исправление: kvpfs (всего исправлений: 1)
Ответ на: комментарий от kvpfs

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

Позволю себе лирическое отступление. На заре моей профессиональной карьеры была очень популярна CORBA, и в частности VisiBroker. Так вот, там был известный глитч когда массивы больше 64k тупо корраптились при пересылке. Знаете какой код я в какой-то момент увидел (в codebase довольно уважаемой конторы, спешу заметить)? «Массивчик больше 64k - зазиповать нахрен». Что произойдёт если ужатый message всё ещё не влезает в 64k - автора не сильно волновало.

К чему я. Стенания и подход ТС мне это очень сильно напоминают…

bugfixer ★★★★
()
Последнее исправление: bugfixer (всего исправлений: 1)
Ответ на: комментарий от kvpfs

Здесь нужно падать

Это уже вызывающий код должен решать, падать или не падать, а просто подавить исключение (показав ошибку пользователю, записать ее в лог и т.д. и т.п.) и выполняться дальше. Но peek, pop и т.д. должны выбрасывать исключение, а не сегфолтиться, кэп.

Udacha
() автор топика

отталкиваясь от такой реализации можно тривиально сделать ту, которую вы хотите. А отталкиваясь от той, которую вы хотите, можно сделать такую какая есть?

cobold ★★★★★
()
Последнее исправление: cobold (всего исправлений: 1)

Писатели стандарта с++ намеренно делают его как можно более уродливым и, как сейчас модно говорить, кринжовым, чтобы на нем писало как можно меньше человек и чтобы он наконец упокоился с миром. Но мыши не сдаются! Кактус еще не доеден!

untitl3d
()

Показываю один раз.

https://godbolt.org/z/xM993vG3d


#include <stdexcept>
#include <vector>
#include <stack>

#include <gtest/gtest.h>

template <typename ... Ts>
struct CheckedVec : public std::vector<Ts...> {
    using base = std::vector<Ts...>;

    decltype(auto) back() {
        if (this->empty())
        {
            throw std::runtime_error{ "back(): empty" };
        }
        return base::back();
    }

    decltype(auto) pop_back() {
        if (this->empty())
        {
            throw std::runtime_error{ "pop_back(): empty" };
        }
        return base::pop_back();
    }
};


TEST(CheckedStack, Throws) {
    std::stack<int, CheckedVec<int>> stack;
    ASSERT_THROW(stack.pop(), std::runtime_error);
    ASSERT_THROW(stack.top(), std::runtime_error);
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Вывод:

[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from CheckedStack
[ RUN      ] CheckedStack.Throws
[       OK ] CheckedStack.Throws (0 ms)
[----------] 1 test from CheckedStack (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 1 test.
Siborgium ★★★★★
()
Ответ на: комментарий от Udacha

Есть абстрактный тип данных стек.

Есть конкретный шаблонный класс std::stack<...>

И нам плевать, как он там внутри устроен.

В С++ – не плевать. Стек это адаптер к указанному параметром контейнеру, ведущий себя так же, как этот контейнер.

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

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

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

в C++ исключения ублюдочные, поэтому их не особо пихали в STL. Чтобы оправдать это непотребство, для дурачков провозгласили принцип «не платим за то, что не используем».

Udacha
() автор топика
26 февраля 2023 г.