Я заметил проблему при использовании clang для компиляции libstdc ++ (т. Е. Реализация стандартной библиотеки C ++ в GNU). Вопрос в том, при условии, что проблема подтверждена, кому я должен сообщить об этом?
Это происходит при назначении шага std::vector<X, A<X>>
и следующие условия:
A<X>
не распространяетсяпри перемещении-назначении и распределителях, используемых исходными и целевыми векторами, не сравнивайте равные.
A MCVE следует (см. live ). К сожалению, он содержит небольшую часть базовой таблицы, и самые важные части обозначены комментариями.
#include <vector>
#include <memory>
#include <type_traits>
struct X {
X() = default;
X(const X&) = default;
// Move constructor might throw
X(X&&) noexcept(false) = default;
// Track calls to assignment functions
X& operator=(const X&) {
putchar('c'); return *this;
}
X& operator=(X&&) noexcept(true) {
putchar('m'); return *this;
}
};
unsigned counter = 0;
template <typename T>
struct A : std::allocator<T> {
template <typename U>
struct rebind { using other = A<U>; };
A() : std::allocator<T>(), id(++counter) {}
// Does not propagate
using propagate_on_container_move_assignment = std::false_type;
// Does not always compare equal
using is_always_equal = std::false_type;
bool operator ==(const A& o) { return id == o.id; }
bool operator !=(const A& o) { return id != o.id; }
unsigned id;
};
int main() {
std::vector<X, A<X>> a(2), rv(2);
a = std::move(rv);
}
Насколько я знаю, clang ++ использует libstdc ++ по умолчанию, а использование libc ++ является обязательным для -stdlib=libc++
,Выполнение приведенного выше кода (опять-таки, построенного с помощью clang и libstdc ++) отображает cc
, что означает, что два элемента rv
назначены для копирования в a
.
Однако, цитирование [container.requirements.general] / 4, таблица 83
«Все существующие элементы объекта либо перемещены, либо назначены, либо уничтожены» *
(Это дополнительно подтверждается [container.requirements.general] / 16, таблица 86 .)
С другой стороны, переключив компилятор на gcc или библиотекув libc ++ мы получаем mm
, что соответствует приведенной выше цитате. Это также происходит путем изменения спецификации исключения X(X&&)
на noexcept(true)
, тогда как спецификация operator =(X&&)
кажется неактуальной.
Я что-то упустил? Если нет, кому я должен сообщить о проблеме? Это либо libstdc ++, либо clang. (Я думаю, что это может быть неочевидно.) Я склонен думать, что это последнее, поскольку, AFAIK, clang должен поддерживать libstdc ++, а не наоборот.
( Примечание :приведенный выше код может выявить, по крайней мере, еще одну проблему, а именно, удаление rebind
из A
приводит к невозможности компиляции clang / libstdc ++, в то время как clang / libc ++ завершается успешно. Мне кажется, что в этом случае вина переворачивается и ложится на libstdc ++, ноэто не часть моего вопроса.)