Почему у std::vector есть 2 конструктора вместо 1 с аргументом по умолчанию?

Я посмотрел cppreference.com и нашел это

vector();
explicit vector( const Allocator& alloc );

почему бы просто не

explicit vector(const Allocator& alloc = Allocator());

1 конструктор вместо 2. Для этого есть причина? то же самое с resize(std::size_t,const T& t) и resize(std::size_t) почему бы просто не resize(std::size_t,const T& t = T())

Ответы на эти две функции на самом деле совершенно разные. Может, спрашивать по одному?

Davis Herring 24.05.2024 22:41

поэтому я подумал об этом, и для метода изменения размера, вероятно, нужно разрешить создание указателя на функцию-член с одним аргументом, а для конструктора я не знаю.

user24551355 24.05.2024 22:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
2
211
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

explicit vector(const Allocator& alloc = Allocator()); потребует, чтобы Allocator был конструируемым по умолчанию и копируемым. Если Allocator не может выполнить одно из этих действий, вы не сможете создать vector по умолчанию.

но требования к распределителю в любом случае требуют, чтобы распределитель имел конструктор копирования

user24551355 24.05.2024 22:59

@user24551355 user24551355 конструктор копирования, да. Но не конструктор по умолчанию

Remy Lebeau 24.05.2024 23:08

если у вас нет конструктора по умолчанию для распределителя, вы даже не можете вызвать конструктор по умолчанию std::vector, так какой у вас пионт? std::vector default condtructor также вызовет конструктор по умолчанию для своего распределителя

user24551355 24.05.2024 23:22

@user24551355 user24551355 тип Allocator тоже является параметром шаблона, и я уверен, что по умолчанию есть конструктор по умолчанию. Но вы правы: если бы вы использовали собственный тип Allocator, для использования первой формы конструктора потребовался бы конструктор по умолчанию.

Mark Ransom 24.05.2024 23:27

Вот почему существует мощный комитет по C++, который занимается стандартизацией, это сложно.

Mark Ransom 24.05.2024 23:29

@MarkRansom C++ — тяжелый человек. Есть так много странных решений.

user24551355 24.05.2024 23:40

@MarkRansom распределитель по умолчанию std::allocator имеет конструктор по умолчанию и конструктор копирования, но другие классы распределителя ДОЛЖНЫ иметь конструктор копирования, это требование распределителя

user24551355 24.05.2024 23:41

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

jamesdlin 25.05.2024 08:42

Если бы конструктор по умолчанию был явным, поскольку это была просто версия с одним аргументом и значением по умолчанию, вы не могли бы инициализировать вектор с помощью {}. Для resize потребуется, чтобы тип элемента был копируемым, а не просто инициализировал значения (технически вставляя значения) новых элементов.

Ответ принят как подходящий

Что касается std::vector<T, Allocator>:
Что касается первого вопроса, то это вопрос полезности и эффективности.
Для вектора() без аргумента:

vector();

Объект распределителя предоставляется шаблоном, по умолчанию используется std::allocator.

Определение можно записать так:

constexpr vector() : elem(nullptr), array_size(0), space(0) {}

Для вектора с объектом распределителя, предоставленным в качестве аргумента:

constexpr explicit vector(const Allocator& alloc) noexcept;

Определение можно записать так:

constexpr explicit vector(const Allocator& alloc) noexcept : elem(nullptr), array_size(0), space(0), v_alloc(alloc) {}

Оба создадут пустой вектор. Если «Allocator» является пользовательским распределителем, т. е. «my_allocator», присвоение объекта через аргумент позволяет использовать характеристики, отличные от характеристик объекта распределителя, предоставленного шаблоном. Если объект распределителя предоставляется по шаблону, все значения внутри объекта имеют значения по умолчанию. Если объект распределителя предоставляется в качестве аргумента, распределитель можно перенастроить перед передачей объекта в качестве аргумента.

Когда вектор создается без аргумента, распределитель создается по умолчанию. Когда вектор создается с аргументом, сначала создается распределитель по умолчанию, а затем копируется из аргумента. Поэтому было бы менее эффективно иметь один конструктор с аргументом, который по умолчанию имеет значение «(const Allocator& alloc = Allocator())».

Что касается второго вопроса, это вопрос эффективности.

«void resize(std::size_t count)» добавляет элементы по умолчанию, когда размер вектора увеличивается. Каждый добавляемый элемент по умолчанию создается с помощью std::allocator_traits:

std::allocator_traits<decltype(v_alloc)>::construct(v_alloc, ptr);

«void resize(std::size_t count, const T& value)» добавляет элементы «value» с помощью конструктора копирования, когда размер вектора увеличивается.

std::allocator_traits<decltype(v_alloc)>::construct(v_alloc, ptr, value)

Если «T()» было указано по умолчанию для «value», добавленные элементы создаются копией, а не конструируются по умолчанию.

Другие вопросы по теме