Подтвердить что ты не робот

Почему элементам std::vector не нужен конструктор по умолчанию?

И как я могу написать собственный класс массива, чтобы не требовать конструктора по умолчанию для его элементов? Прямо сейчас, когда я делаю новый [] для выделения пробела, мне нужен конструктор по умолчанию.

std::vector нет.

Как они делают эту магию?

4b9b3361

Ответ 1

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

Вы можете написать такой класс точно так же: каждый раз, когда вам нужно построить новый элемент в вашем массиве, попросите пользователя предоставить элемент для копирования. В этом случае создание этого исходного элемента становится ответственностью пользователя.

Каждый раз, когда он выглядит так, как будто std::vector "требует" конструктора по умолчанию от вас, это просто означает, что где-то вы полагались на аргумент по умолчанию некоторых методов vector, то есть именно вы пытались использовать по умолчанию, построить элемент, а не вектор. Сам вектор снова не будет пытаться создавать элементы по умолчанию.

Чтобы избежать требования конструктора по умолчанию при распределении памяти, стандартная библиотека выделяет необработанный неинициализированный блок памяти, а затем сразу же копирует новые элементы в этом необработанном блоке памяти (что-то new[] не может сделать). Эта функциональность инкапсулируется в классе std::allocator. Вы также можете использовать std::allocator в своем коде, что означает, что "волшебство" также доступно вам.

Примечание: Вышеприведенное относится к предварительной версии С++ 11 для языка С++. С++ 11 многое изменило. И эти изменения создают ситуации, в которых std::vector может использовать встроенные конструкторы по умолчанию.

Также стоит отметить, что даже исходная спецификация С++ 98 позволила реализациям использовать перегрузку функций вместо аргументов по умолчанию для реализации стандартного интерфейса библиотеки. Это означает, что формально можно иметь допустимую реализацию С++ 98 std::vector, которая использует внутренние конструкторы внутри.

Ответ 2

std::vector требует, чтобы элемент имел конструктор по умолчанию, если вы используете его таким образом, который требует конструктора по умолчанию. Таким образом, этот код (украденный из удаленного ответа) не будет компилироваться, потому что X не имеет значения по умолчанию ctor:

#include <vector>

struct X
{
  X(int) {}
};

int main(void)
{
  std::vector<X> x(1); // vector of length 1, second argument defaults to X() !!
  return 0;
}

Но если вы пишете main следующим образом:

int main(void)
{
  std::vector<X> x; // make empty vector
  x.push_back(X(1));
  return 0;
}

Тогда он отлично работает.

Ответ 3

Вы можете выделить блок байтов, а затем использовать размещение new, чтобы создать новый экземпляр T (ваш параметрический тип) через copy конструктор (конечно, не конструктор по умолчанию), когда новые элементы переносятся обратно на вектор. Это не позволит сделать "вектор N-инициализированного по умолчанию Ts" (который может сделать std::vector, поэтому для требуется, чтобы T имел конструктор по умолчанию для этой цели), но вы могли бы сделать векторы, которые начинаются пустым и могут накладываться на них.