2012-03-02 1 views
2

Рассмотрим следующий код:Предполагается, что моя перегрузка `swap` должна использоваться? Является ли это ошибкой libstdC++ (GCC)?

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

struct A { 
    int val; 

    bool operator<(const A& other) const { 
     std::cout << "operator\n"; 
     return val < other.val; 
    } 
}; 

void swap(A& a, A& b) { 
    std::cout << "foo\n"; 
    std::swap(a.val, b.val); 
} 

int main() 
{ 
    std::vector<A> a(2); 
    a[0].val = 10; 
    a[1].val = -1; 

    std::sort(a.begin(), a.end()); 
} 

11 C++ в std::sort мест ValueSwappable требования к аргументам итераторов двигаться семантику и ничего, подразумевая, что std::sort будет «гарантировано», чтобы выполнить обмен, если элементы должны перемещаться. И 17.6.3.2/3 предполагает, что моя перегрузка определенно должна быть выбрана в этом случае.

  • Это правильно?

clang 3.1 SVC libC++ выбирает мой swap (то есть я вижу «foo»); GCC 4.6.3 libstdC++ этого не делает.

  • Является ли это ошибкой GCC (при условии, что моя стандартная интерпретация верна)? Или я чего-то не хватает?
+0

** Примечание: ** Я полагаю, [этот способ 'swap'ping не рекомендуется] (http://stackoverflow.com/questions/11562/how-to-overload-stdswap), но я все равно как знать, что здесь происходит. –

+0

Похоже, что ADL не используется, чтобы найти перегруженную версию 'swap' с gcc, где, как clang использует ADL. Были некоторые комментарии к потоку, который вы указали на это шоу, что использование ADL для поиска 'swap' на' std :: sort' не является стандартным среди компиляторов. – Jason

+0

@ Джейсон: Почему ADL вообще будет задействован для бесплатной функции в глобальном пространстве имен? –

ответ

6

11 C++ в std::sort местах ValueSwappable требования к аргументам итераторов, двигаться семантика и ничего, подразумевая, что std::sort является «гарантирован», чтобы выполнить обмен, если элементы должны быть перемещены.

Я не вижу, что гарантия. Кто сказал, что std::sort не может использовать семантику перемещения вместо свопов? На самом деле, после просмотра стандарта для дословной спецификации, я считаю, что это именно то, что происходит:

Требуется: RandomAccessIterator должны удовлетворять требования ValueSwappable (17.6.3.2). Тип *first должен удовлетворять требованиям MoveConstructible (таблица 20) и MoveAssignable (таблица 22).

Обратите внимание, что итераторы должны быть ValueSwappable, а не элементы они указывают.

+0

@FredOverlow: Ну, элементы все еще должны быть действительными. Таким образом, обмен должен каким-то образом войти в него, нет? _ [edit: и диапазон должен оставаться в своем существующем месте в памяти, IIRC] _ Хотя ваш ответ заставил меня понять, что проблема _might_ заключается в том, что если 'std :: sort' делает ходы для обмена, я, возможно, должен быть беря rvalue refs в мою функцию 'swap'? –

+0

Нет, 'swap' не принимает ссылки rvalue. Вас может обмануть в мысли, что основная операция алгоритмов сортировки - это замена элементов, но если вы посмотрите на фактическую реализацию 'std :: sort', скорее всего, вы не найдете ни одного вызова' swap'. (Например, сортировка кучи не основана на свопах.) Что происходит, когда вы предоставляете конструктор перемещения и переместите оператор присваивания, который печатает на консоль? Они должны быть вызваны, независимо от того, выполняется ли 'sort' в терминах' swap' или нет. – fredoverflow

+0

Полагаю, я смущен тем, что «std :: sort» может работать вообще. Где значения могут перемещаться, если не в какое-либо место в данном диапазоне? Таким образом, требуется обмен? –

6

Я отправляю это как ответ, потому что у меня нет репутации для комментариев.

Как указывал @FredOverflow, libstdC++ использует операции перемещения конструкторов и операторов присваивания при сортировке. Тем не менее, мне показалось странным, что он не использует ADL для кода pre C++ 11, чтобы люди могли подключать оптимизированные функции свопинга.

+2

Получите некоторую репутацию и начните комментировать :) –

+0

Является ли вызов 'swap' быстрее, чем ряд назначений в C++ 03, зависит от типа и независимо от того, специализируется ли он' std :: swap' (или предоставляет функция 'swap' в собственном пространстве имен). Это, вероятно, очень сложно или даже невозможно понять во время компиляции. Например, интрортация списка ints будет намного медленнее с помощью свопов вместо серии назначений. – fredoverflow

+0

Но ADL встроен в компилятор, и разработчики библиотеки уже используют перегрузку подкачки в каждой коллекции. Предоставление swap-заглушки значительно помогло бы людям в том, что использовать контейнеры со смысловой семантикой, сохраняя код быстро. – Pedro

 Смежные вопросы

  • Нет связанных вопросов^_^