Кресты / Говнокод #19663 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
#include <vector>

template <typename T>
void FreeAll( T & t ) {
    T tmp;
    t.swap( tmp );
}

Запостил: 3_dar 3_dar, (Updated )

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

  • void *p = malloc(100);
    FreeAll(p);
    А обещали, что всё почистит...
    Ответить
    • А мне показалось, что название функции переводится как «все свободны».
      Ответить
    • ничего там не утекает (если только в это не контейнер обычных указателей), просто удаляется неявно.
      Ответить
      • Ну это даже не говнокод для некоторых контейнеров...

        У вектора capacity только так срезать можно. И function только так можно почистить...
        Ответить
            • Говнокод от ОПа не помогает. Там просто обмен указателями при свапе. Я пробовал.

              Вот вам от меня:
              template <typename T>
              void FreeAll( T & t ) {
                  t.reserve(0);
              }

              Явно ID, но в моем случае работало. Всем няшек и бобра!
              Ответить
              • ну да. Свап указателей с временной переменной, которая удаляется при выходе из метода и, соответственно, подчищает память
                Ответить
                • Не, мой метод работает даже на не пустой коллекции, как и shrink_to_fit. А этот угробит данные
                  Ответить
                  • еще раз. Код ОПа призван очистить существующую коллекцию, освобождая память. Ровно это он и сделает.

                    shrink_to_fit, как уже было сказано, может предложить лизнуть тунца: "It depends on the implementation if the request is fulfilled.".

                    а reserve(0) уж точно предложит вкусить лососца: "If new_cap is greater than the current capacity(), new storage is allocated, otherwise the method does nothing."
                    Ответить
                    • Кстати последние стандарты объявляют выделение/освобождение памяти ненаблюдаемым поведением, даже если там есть сайд эффекты.

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

                        короче, серебряная пуля:
                        template <typename T>
                        void FreeAll( T & t ) {
                            volatile T tmp;
                            t.swap( tmp );
                        }
                        Ответить
                        • А как ты докажешь, что он этого не сделал? Компилятор может делать что угодно если не трогать наблюдаемое поведение. Представь себе: конструктор временной переменной выделяет столько же памяти, сколько и в оригинальном векторе, свап, деструктор, и capacity оригинального вектора не изменилось.

                          Даже серебрянная пуля не поможет. Хотя она и не соберётся, так как swap с волатильными векторами не работает.
                          Ответить
                          • в таких моментах остается расчитывать на адекватность производителей компиляторов
                            Ответить
                      • > объявляют выделение/освобождение памяти ненаблюдаемым поведением
                        > не делать больше ничего
                        Погодите, а из этого не следует, что компилятор может официально сгенерировать программу, в которой память будет безбожно течь? Скажем, вообще все освобождения выпилить, только код деструкторов оставить.
                        Ответить
                        • Там несколько сложнее в стандарте. Фактически оптимизировать можно выделение памяти в том случае, когда можно убедится что это не сломает программу (читай, когда для оптимизации доступна пара выделение/освобождение)

                          Оптимизировать выделение памяти компиляторы умели давно ( http://goo.gl/RZ2FVt , советую посмотреть, что делает гцц4.8), просто в новом стандарте разрешили при этом игнорировать побочные эффекты, чтобы всякие логирующие аллокаторы не ломали оптимизацию.
                          Ответить
                          • Посмотрел ссылку и опечалился. Теперь буду вместе с Пи ходить и ворчать про C++, а заодно и про C.

                            Я ассемблерные штуки почти не знаю, но это же питушня какая-то. Насколько я понял, компилятор из тормозного кода с доступом в потенциально чужую память сделал быстрокод с закэшированным результатом. И если добавить main, который печатает foo(1), внутри сразу распечатается 55 без вызова всяких там функций.
                            Но если добавить if(ip == NULL) return 0; после malloc, то malloc будет вызываться всегда только ради проверки наличия памяти и foo не заинлайнится:
                            int foo(int x) {
                              int*ip;
                              if(!(ip=malloc(10*sizeof(int))) return 0;
                              free(ip);
                              return 10*x + 45; // оптимизировано
                            }
                            Ответить
                            • > то malloc будет вызываться
                              Зачем? Вызов ненастоящего malloc'а всегда успешен... Значит проверку на нулл можно с чистой совестью выкинуть.
                              Ответить
                              • > Вызов ненастоящего malloc'а
                                Так и поехать можно.

                                Его "ненастоящность" как-то зафиксирована? (макросы/стандарт/директивы) Или человек компилирует в GCC x.x.x, видит, что соптимизировалось и добавляет комментарий
                                // Мнимый malloc. Конпелировать только в GCC x.x.x, иначе бомбанёт
                                Ответить
                                • > Его "ненастоящность" как-то зафиксирована?

                                  Компилятором. Он же видит, что можно вызов настоящего malloc заменить на ненастоящий. Затем замечает, что ненастоящий malloc всегда успешен и выкидывает проверку.

                                  Кстати, шланг оптимизирует даже с проверками.
                                  Ответить
                                  • Ну что, осталось оптимизировать записи в файл... Если прога что-то пишет в файл, а потом удаляет его, к примеру.
                                    Ответить
                                    • Ну, теоретически то, что возвращает tmpfile можно считать эффективно уникальным и недоступным иным способом. На линухе ЕМНИП оно даже не создаёт реальный файл.
                                      Ответить
                                      • Ну и остаётся оптимизировать ненастоящего пользователя... Если юзер увидев X всяко нажмёт Y, то зачем ему показывать X, когда можно сразу сделать Y...
                                        Ответить
                              • >> ненастоящего malloc

                                и он выделяет ненастоящую память?
                                Ответить
                            • > Теперь буду вместе с Пи ходить и ворчать про C++

                              Ты будешь в неплохой компании: с wvxvw и Тарасом.
                              Ответить
                  • Чтобы не угробить данные:
                    template <typename T>
                    void Shrink(T &t)
                    {
                        T tmp(t);
                        tmp.swap(t);
                    }
                    Ответить
                      • Оператор обновления данных. А то вдруг DRAM хуёво регенерируется...
                        Ответить

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

Где здесь C++, guest?!

    А не использовать ли нам bbcode?


    8