Оптимизация контейнера: почему аргументы метода контейнера STL больше не используют allocator:: const_reference typedef?

ДО ТОГО, ЧТО ВЫ ПРОЧИТАЕТЕ: const_reference является typedef и не нуждается в const T&, как вы можете видеть в std::vector<bool>::const_reference = bool. Пожалуйста, имейте это в виду, читая остальное, чтобы понять это правильно (как это предложено в кометах, это трудно для многих людей).


Я хотел использовать контейнеры STL для простых типов (например, int) и обнаружил, что они используют недооптимальный const T& "анти-шаблон" - он хорошо работает для больших классов, но не оптимален для простых/основные типы, если они не включены - рассмотрите встроенную систему, например на ARM/ATSAM4L, с инстанцированием.

Вопрос: почему именно? vector::push_back изменен с аргументом (const value_type&) вместо (Allocator::const_reference), так как С++ 11? Он должен быть одинаковым для общего allocator, но при этом другой способ помог мне написать собственный распределитель (или специализированную специализацию) для фундаментальные типы, которые определяли бы const_reference как сам тип (см. vector<bool>::const_reference = bool).

Вопрос 2: Есть ли какой-либо адаптерный класс, который может сделать это для меня?

Что-то вроде этого:

template<class T, class base = std::vector<T> >
  class myvect: protected base {
public:
    typedef T const_reference;
    void push_back(const_reference value) {
        base::push_back(value); }}

Конечное использование будет таким:

typedef void (*action_t)(void*,int);
extern "C" void work(void *, action_t);
work(&vect, (action_t)&vect::push_back);

( примечание: игнорировать возможные проблемы с литьем в предыдущем блоке кода, надеюсь, вы получили эту идею.)

EDIT: vector::const_reference определяется непосредственно как const value_type&, но, на мой взгляд, должен быть определен как Alloc::const_reference, который затем можно легко изменить (vector<int, MyAllocator<int> >). (Это было изменено в С++ 11, оно было определено как Alloc:: const_reference, но теперь const value_type &)

РЕДАКТИРОВАТЬ: func(const T&) иногда описывается как "анти-шаблон" здесь, в stackoverflow, потому что он не оптимален для базовых типов без инкрустации (да, компилятор генерирует оптимальный код даже для func(const int&), если он встраивается, но вот что IF. func(int) будет лучше работать)


ЗАКЛЮЧЕНИЕ: Сама проблема, по-видимому, связана с поведением const и, следовательно, const T&. const на самом деле не означает, что он не изменится, но не изменится, и поэтому const T& необходимо (и четко определено и использовано) как тип возврата для многих методов. Создание пользовательского класса адаптера представляется наилучшим способом оптимизации и, как представляется, широко принято, что std::vector<bool> является нечетным исключением, которое должно быть в отдельном классе (например, dynamic_bitset).

Ответ 1

Его немного длиннее в комментарии, поэтому я буду использовать "ответ", чтобы говорить об этом, но на самом деле это не ответ.

Функция, которую вы хотите изменить,

Вы хотите, чтобы у вас была возможность избежать идиомы "перейдите по ссылке на const" в определенных методах, чтобы избежать "замедления", вызванного операцией указателя для небольших типов, или прямой копии. Примечательно, что для push_back, если у push_back был параметр с настраиваемым типом (по типу шаблона в типе контейнера, как и параметр шаблона распределителя), тогда это может заставить вас чувствовать себя хорошо.

Можно было бы предоставить функцию, которую вы хотите, определенно, например, используя тот же метод, что и параметр шаблона распределителя, может быть имя типа, которое указывает, какой тип используется в параметре "push back".

Но он не был спроектирован таким образом, потому что он кажется сложным, и это не стоит того. Это не стоит из-за оптимизаций компилятора, которые будут вызывать много накладных расходов для основных типов, потому что статический анализ намного проще запускать на основных типах.

Во-вторых, "потерянное время" передачи значения int по сравнению с копированием в параметрах метода считается специфичностью платформы, которая не может быть проверена на уровне "виртуальной машины" (уровень, на котором языковые авторы имеют поместить себя). Не говоря уже о "преждевременной оптимизации" здесь, что привело бы к откровенному проникновению кода в качестве разумного компромисса для общего назначения, оно было полностью выселено. Это связано также с тем, что во время разработки вы считаете фундаментальные типы, такие как раритеты и бесконечность возможных типов, которые могут содержаться.

пс: наконец, использование typedef как части распределителя кажется очень плохим разделением ответственности, поскольку его собственный параметр шаблона кажется более чистым, потому что он не имеет ничего общего с распределением, а имеет какое-то отношение к вариантам реализации конкретных методов контейнер.

ps2/Edit: Я хочу добавить, как сказано в комментариях, что vector<bool>::const_reference нельзя считать примером того, что можно сделать, потому что это была ошибка в стандарте и на самом деле является нарушением требования STL , что контейнер определяет ..::reference как T&. Еще одно доказательство проблемы заключается в том, что vector<bool>::reference (not const) не является bool, это неуказанный класс (_Bit_reference в gcc), который служит прокси для доступа и мутации бит, упакованного в вектор, который будет служить в качестве поддержки хранения для "виртуального" значения bool, которое создается как существующее. Эти странности нельзя портировать на общий вектор, поскольку они не учитывают широкие требования STL. Но это не делает недействительным ортогональный подход, как я уже упоминал с pass_for_copy_param_type, который может быть параметризуемым, новым typedef и использоваться взамен в некоторых местах (подходящих), где "const value_type &" написано сегодня. Но это именно то, что я упоминал ранее. Я уверен, что определенно не стоит так много для этого.

Ответ 2

Изменение значения const_reference приведет к поломке семантики методов, возвращающих ссылку const:

std::vector<int> my_vector(100);
 // this needs an lvalue ref
my_vector[42]++;

// I want to track this value
std::vector<int>::const_reference i = my_vector[3];
  // I expect i to be be 1 after this
my_vector[3]++;

Ответ 3

Разрешение изменения типа const_reference нарушает совместимость с требованиями std::vector и контейнера. Стандарт явно предполагает, что const_reference является ссылкой и использует это много раз, например. семантика данных() и front(). В пункте 23.3.6.4 говорится: "Для непустого вектора, data() == & front()". Это сделает вашу модификацию недействительной, поскольку с вашей модификацией функция front() больше не вернет ссылку на выделенную память и, следовательно, адреса будут отличаться. Фактически, это был бы адрес временного объекта.

Я также думаю, что большинство компиляторов оптимизирует любые дополнительные затраты на использование const & прочь.

std::vector <bool> - плохой пример, потому что это не модель контейнера в смысле STL. Большинство людей согласны с тем, что оно не должно определяться в стандарте, например. https://isocpp.org/blog/2012/11/on-vectorbool.