Пользовательская функция подкачки НЕ вызывается в алгоритме сортировки stl [duplicate]

GAE - это общедоступная среда хостинга и содержит файлы WAR от нескольких пользователей. Очень вероятно, что несколько файлов WAR размещены в одной JVM, потому что нереста процесса на WAR просто смешно. Таким образом, единственный способ изолировать каждый файл войны - через пользовательский загрузчик классов для каждого файла WAR.

Теперь предположим, что отражение разрешено. Вы могли бы затем пройти иерархию загрузчика классов и перечислить классы / методы из файлов WAR, принадлежащих разным пользователям. Очевидно, это большая проблема.

17
задан Petter 8 January 2013 в 12:16
поделиться

3 ответа

Для небольших диапазонов реализации std::sort в реализациях stdlibc ++ (и других стандартных библиотек GCC) повторяется для сортировки вставки по соображениям производительности (она быстрее, чем quicksort / introsort на небольших диапазонах).

Тип вставки GCC реализация, в свою очередь, не подкачки через std::swap - вместо этого она перемещает целые диапазоны значений за раз, вместо того, чтобы менять их по отдельности, что потенциально экономит производительность. Соответствующая часть здесь (bits/stl_algo.h:2187, GCC 4.7.2):

typename iterator_traits<_RandomAccessIterator>::value_type
  __val = _GLIBCXX_MOVE(*__i);
_GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + 1);
*__first = _GLIBCXX_MOVE(__val);

_GLIBCXX_MOVE совпадает с std::move из C ++ 11, а _GLIBCXX_MOVE_BACKWARD3 - std::move_backward - однако это только в случае, если определено __GXX_EXPERIMENTAL_CXX0X__; если нет, то эти операции прибегают к копированию, а не к перемещению!

Что это значит, переместите значение в текущей позиции (__i) во временное хранилище, а затем переместите все предыдущие значения с __first до __i вверх, а затем повторно вставьте временное значение в __first. Таким образом, это выполняет команды n в одной операции, вместо этого для перемещения значений n во временное местоположение:

  first           i
+---+---+---+---+---+---+
| b | c | d | e | a | f |
+---+---+---+---+---+---+
                  |
  <---------------+


  first           i
+---+---+---+---+---+---+
| --> b-> c-> d-> e-> f |
+---+---+---+---+---+---+


  first           i
+---+---+---+---+---+---+
| a | b | c | d | e | f |
+---+---+---+---+---+---+
  ^
19
ответ дан Konrad Rudolph 16 August 2018 в 00:13
поделиться
  • 1
    Так что если перемещение намного дороже, чем своп для вашего типа, то стратегия GCC - это пессимизация. Но это «ваша собственная ошибка». для оптимизации обмена, но не оптимизации движения, не так ли? – Steve Jessop 8 January 2013 в 13:04
  • 2
    @SteveJessop Да, и да. – Konrad Rudolph 8 January 2013 в 13:05
  • 3
    Спасибо! И спасибо, Стив, за хороший вопрос в комментарии! – Petter 8 January 2013 в 14:34
  • 4
    Просто уточнить для себя (и для других). «Оптимизация перемещения» означает запись конструктора перемещения, не так ли? – Petter 8 January 2013 в 14:36
  • 5
    @Ben вы действительно хотите переместить назначение также. – Marc Glisse 8 January 2013 в 19:37

В зависимости от типа, обмен может быть дороже, чем переадресация (в C ++ 98 простое назначение). Стандартная библиотека не имеет способа обнаружить эти случаи. По крайней мере, в C ++ 11 решение понятно: реализуйте оператор присваивания move для всех классов, где вы реализуете swap.

3
ответ дан Marc Glisse 16 August 2018 в 00:13
поделиться

Я изменил код, чтобы быть более подробным. Сортировка для 20 элементов использует много свопов, использует конечную копию назначения. Сортировка для 4 элементов использует только назначение и копирование. Не знаю о спецификациях, но может быть что-то еще.

#include <algorithm>
#include <iostream>
#include <vector>

namespace my_space
{

struct A
{
    double  a;
    double* b;
    A()
        : a(0)
        , b(NULL)
    { }
    A(const A &rhs)
        : a(rhs.a)
        , b(rhs.b)
    {
        std::cerr << "copy" << std::endl;
    }
    A& operator=(A const &rhs)
    {
        if(this==&rhs)
                return *this;
        a = rhs.a;
        b = rhs.b;
        std::cerr << "=" << std::endl;
        return *this;
    }
    bool operator<(const A& rhs) const
    {
        return this->a < rhs.a;
    }
};

void swap(A& lhs, A& rhs)
{
    std::cerr << "My swap.\n";
    std::swap(lhs.a, rhs.a);
    std::swap(lhs.b, rhs.b);
}

} // namespace my_space

int main()
{
    const int n = 20;

        std::cerr << "=== TEST CASE: n = " << n << std::endl;
    std::cerr << "=== FILL ===" << std::endl;
    std::vector<my_space::A> vec(n);
    for (int i = 0; i < n; ++i) {
        vec[i].a = -i;
    }

    std::cerr << "=== PRINT ===" << std::endl;
    for (int i = 0; i < n; ++i) {
        std::cerr << vec[i].a << " ";
    }
    std::cerr << "\n";

    std::cerr << "=== SORT ===" << std::endl;
    std::sort(vec.begin(), vec.end());

    std::cerr << "=== PRINT ===" << std::endl;
    for (int i = 0; i < n; ++i) {
        std::cerr << vec[i].a << " ";
    }
    std::cerr << "\n";
}

Выходы

=== TEST CASE: n = 4
=== FILL ===
copy
copy
copy
copy
=== PRINT ===
0 -1 -2 -3
=== SORT ===
copy
=
=
copy
=
=
=
copy
=
=
=
=
=== PRINT ===
-3 -2 -1 0

И

=== TEST CASE: n = 20
=== FILL ===
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy
=== PRINT ===
0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19
=== SORT ===
copy
My swap.
My swap.
My swap.
My swap.
My swap.
My swap.
My swap.
My swap.
My swap.
My swap.
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
copy
=
copy
=
copy
=
copy
=
copy
=
=== PRINT ===
-19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0
1
ответ дан Notinlist 16 August 2018 в 00:13
поделиться
  • 1
    BTW: Сортировка SGI использует en.wikipedia.org/wiki/Introsort , которая в какой-то момент меняет тактику. – Notinlist 8 January 2013 в 12:37
  • 2
    Возможно, вам потребуется реализовать сортировку кучи, поэтому вы можете использовать только своп. Для эффективной стабильной сортировки вам понадобятся копии и / или задания. Существует устойчивая сортировка на месте, называемая «сортировка слияния на месте». который может использовать только swap, но он несколько медленнее (n logn logn, а не n * logn). – Notinlist 8 January 2013 в 12:50
  • 3
    Но std::sort не обязательно должен быть стабильным. Таким образом, замена по сравнению с не заменой не влияет на сложность здесь. – Steve Jessop 8 January 2013 в 13:03
  • 4
    Для 20 элементов моя собственная реализация сортировки кучи использовала 62 свопа и ничего больше. В ST ++ ST используется 99 операций (35 копий, 19 заданий, 10 swap, 35 delete). Не считайте это оружейным классом! В нем не хватает многих функций удобства использования. Ссылка: pastebin.com/5SVm6Tz9 – Notinlist 8 January 2013 в 16:24
Другие вопросы по тегам:

Похожие вопросы: