1. C++ / Говнокод #14719

    +132

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    template <typename T>class CleverPtr
    {
      T* ptr;
    public:
      ~CleverPtr () { delete ptr; }
    
      CleverPtr () : ptr(new T) {}
    
     CleverPtr(const CleverPtr& other) 
        :ptr(new T)    // <--- если напрягает, используйте делегирующий конструктор с++11
      {
        operator =(other); 
      }
    
      CleverPtr& operator = (const CleverPtr& other) 
      {
        if (this != &other)
           *ptr = *other.ptr;
         return *this;
      }
     
    };

    оттуда

    Запостил: LispGovno, 20 Февраля 2014

    Комментарии (31) RSS

    • Очень клевый указатель
      Ответить
    • Он очень умно создаёт утечки?
      Ответить
      • где?
        Ответить
        • Упс, не заметил разыменовывания на 18 строчке. Зато оператор= не exception-safe, возможности создать объект не по умолчанию и из голого указателя нет.

          Смысла в этом не очень вижу, разве что как обёртку над PIMPL указателями, чтобы не писать свои деструктор и оператор присваивания.

          Куда интереснее была бы идея COW указателя.
          Ответить
          • > Куда интереснее была бы идея COW указателя.
            А как он узнает, что в объект кто-то писал? А по любой неконстантной разадресации делать detach() - не комильфо.
            Ответить
            • Ссылку всегда возвращать ко нстантную при -> и *, а если хочется записать - делать это отдельным методом или даже заводить отдельный указатель записи.

              Хотя идея далеко не благая, но в ад всё равно ведёт.
              Ответить
              • По идее можно запилить этот cow_ptr как обертку для обычного shared_ptr. Предложенный тобой отдельный метод (назовем его modify()) будет проверять счетчик, и если там не 1 - делать ptr.reset(new T(*ptr)). Вот собственно и все.
                p.modify()->setX(100500);
                p->setX(42); // нельзя, т.к. мы возвращаем const
                Ответить
    • Осталось понять, чем это отличается от передачи объекта по значению, помимо бессмысленной работы с кучей и невозможности задать параметры конструктора.
      Ответить
      • контекст: http://www.gamedev.ru/flame/forum/?id=186255
        Ответить
        • > Я тут предлагал сделать так, чтобы в любом классе в качестве оператора = по умолчанию было что-то типа
          Ну нахуя? Там и так по умолчанию генерится адекватный оператор присваивания и копирующий конструктор...

          Писать деструкторы, операторы присваивания и копикторы/мувикторы приходится только в низкоуровневых классах. В остальных случаях почти всегда хватает дефолтовых.
          Ответить
          • > Ну нахуя? Там и так по умолчанию генерится адекватный оператор присваивания и копирующий конструктор...

            про классы, в которых не надо писать свою логику в деструкторе, и так ясно, не про них речь
            Ответить
            • А в каких классах надо писать логику в деструкторе помимо Тарасомассива да RAIIшных оберток над всякими ресурсами и блоками памяти?
              Ответить
              • Есть дофига и больше ситуаций типа "сделал А - сделай и Б", типа там пометить объект - снять пометку с объекта.
                Правда на 90% в них вообще T(T) не нужен, но опять же - а чего это я должен руками банить обоих, и T(T) и =(T)?
                Ответить
                • > руками банить обоих
                  Скажите, а boost::noncopyable не может спасти гиганта мысли?
                  Ответить
                  • > boost
                    Ответить
                    • Блеать, ну скопируй этот файлик, если влом буст ставить. Там строк 20 в нем, и он ни от чего не зависит.
                      Ответить
                • > сделал А - сделай и Б
                  Ну это само собой: откаты транзакций (RAIIшная обертка над транзакцией), тот же std::lock_guard (RAIIшная обертка над lock/unlock).

                  Но это же все низкоуровневые классы, которые пишутся один раз...

                  > пометить объект - снять пометку с объекта
                  Можно пример из практики?
                  Ответить
                  • > Можно пример из практики?

                    Долго рассказывать, но попробую.
                    Задача такая, есть дохрена большой, допустим, граф, дохренища большой, размером N. И надо, допустим, сделать обход в ширину из вершины А, чтобы найти путь в вершину, обладающую свойством Б. И вы знаем, что обойдём мы при этом лишь небольшую часть графа, размером M.
                    Короче, надо как-то помечать обойдённые вершины. И уложиться в O(M). Как?

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

                    1, брутальное. Просто заводить булевый массив размера N и мемсетом занулять. Алгоритмическая сложность уже не та, но мемсет отработает сравнительно быстро.
                    2, хеш, хранящий обойдённый вершины, быстро обнуляется, быстро ищется. Переубийство, я считаю.
                    3, каждая вершина хранит момент времени (номер тика), когда её в последний раз обходили, то есть вместо if passed[i] надо писать if passed[i]==currentTick. Проблема в том, что тик может переполниться за край и тогда неверно отработается "вершина помечена", хотя на самом деле мы её помечали 2**32 тиков назад. Решения:
                    2а). инт64, тогда надо долго ждать перед переполнением. Но это как-то антиинженерно, как сказали в треде, где сия проблема обсуждалась.
                    2б). вот тут ваще пиздец и в это надо врубаться специально, но короче против вершин, хранящих очень старое значение, есть такой приём: после каждой пометки вершины как обойдённной, надо одну из других вершин пометить числом currentTick-1, так, чтобы через N тиков все вершины содержали число, не меньшее, чем currentTick-N-1
                    3) моё решение брутально и тупое, но я пока не скажу
                    Ответить
                    • > Проблема в том, что тик может переполниться за край и тогда неверно отработается "вершина помечена", хотя на самом деле мы её помечали 2**32 тиков назад.
                      В postgres есть аналогичная проблема с номерами транзакций. Если ты выключишь autovacuum, который помимо сжатия таблиц меняет айдишки слишком старых транзакций на специальное число (то ли 0 то ли -1), которое заведомо меньше любых реальных xid'ов, то через 2^31 транзакций кровь-кишки-полбазы-пропало.

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

                      > моё решение брутально и тупое, но я пока не скажу
                      Набиваешь в какой-нибудь контейнер, умеющий вставку за O(1) объекты, которые в деструкторе снимают метки с соотв. узлов графа?
                      Ответить
                      • > Набиваешь в какой-нибудь контейнер, умеющий вставку за O(1) объекты, которые в деструкторе снимают метки с соотв. узлов графа?
                        Ёпт, ты догадливый.
                        Контейнер этот - тарасомассив. Размер графа известен, так что сколько памяти выделить - тоже известно.
                        Осталось только таскать ссылку на этот массив во всех методах.
                        Ответить
          • > низкоуровневых классах
            а Тарас тебе что, сраный быдлокодер-формошлёп?
            велосипед - вообще самый экологичный вид транспорта, и для здоровья полезно, и в квартиру можно занести
            Ответить
            • То есть новые классы со своими деструкторами писать уже не надо вообще лол?
              Я вроде бы уже упоминал, что мои контейнеры не имеют аналога в СТЛ, и только поэтому и писались.
              Ответить
              • >>быдлокодер-формошлёп
                В ответ на это нужно сказать что-нибудь резкое.
                Ответить
              • в js есть единственный вид контейнера, который геройски собой покрывает даже не контейнеры.
                в с++ с бустом штук 30 точно наберётся (а то, может, и того больше)

                и только Тарасу всё мало, нам нужны велосипеды с треугольными колёсами! как же мы раньше жили без них? надо ещё поддрочить и поднатужиться, а потом ныть, бля как же так, почему мой треугольный велосипед падает на пятиугольных шоссе!

                хотя нет, продолжайте
                Ответить
                • буст не нужен
                  Ответить
                  • у меня нет Intel(R) Xeon(R), но сейчас я вам всем докажу насколько он не нужен с помощью этой зажигалки и куска кремния
                    Ответить
                    • Смотрите, на столе лежит новенький Intel(R) Xeon(R), сейчас я с помощью канистры бензина и зажигалки докажу, что это просто бесполезный кусок кремния.
                      Ответить
          • Согласен с вами. Но нужно наконец дождаться из буста из его песочницы наконец clone_ptr и тогда действительно больше не придется почти писать конструктора, да деструктора.
            Ответить
    • обычно наоборот, из конструктора копирования вызывается оператор присваивания, чтобы избежать повторного кода
      Ответить
    • Где-то я это уже видел.
      Ответить
    • Въебал дохуя минусов.
      Ответить

    Добавить комментарий