Почему std :: vector не может содержать постоянные объекты? - PullRequest
2 голосов
/ 06 апреля 2020

Я не уверен, почему следующий код не может существовать:

int main()
{
    std::vector<const int> v;
    v.reserve(2);
    v.emplace_back(100);
    v.emplace_back(200);
}

Теоретически, reserve() не создает ничего, в отличие от resize(). Кроме того, emplace_back() создает объекты «на месте», поэтому ни один из этого кода не записывает поверх уже созданного константного объекта.

Несмотря на то, что даже запись первой строки, std::vector<const int> v;, уже приводит к ошибка компиляции. Почему вообще не разрешено иметь std::vector констант?

Ответы [ 2 ]

1 голос
/ 06 апреля 2020

Хотя «почему» лучше всего читать здесь , есть несколько простых способов получить то, что вы хотите:

template<class T>
class as_const {
    T t;
public:
    as_const(T& t_): t(t_) {}
    as_const(const as_const&) = default;
    as_const(as_const &&) = delete;
    as_const& operator=(const as_const&) = default;
    as_const& operator=(as_const&&) = delete;

    operator const T&() const {
       return t;
    }
    const T& operator*() const { 
    // Or just a get method, anyway it's nicer to also have an explicit getter
       return t;
    }
};

std::vector<as_const<int>> vec;
vec.reserve(2)
vec.emplace_back(100);
vec.emplace_back(200);

Вы даже можете решить, «насколько постоянным» должна быть ваша оболочка и предоставьте конструкторы перемещения (обратите внимание, что t не является постоянным per se в as_const), если вы считаете, что это целесообразно для вашего варианта использования.

Обратите внимание, что вы не можете запретить перераспределение вашего вектора таким образом. Если вы хотите это сделать (и не хотите использовать массив размера во время компиляции, поскольку теперь ваш размер только во время выполнения), взгляните на std::unique_ptr<T[]>. Но обратите внимание, что в этом случае вам сначала нужно создать изменяемый вариант, а затем повторно установить его в константном варианте, поскольку базовый массив инициализируется по умолчанию, и после этого вы ничего не можете изменить.

Конечно, есть и возможность работы с распределителем и запрет перераспределения. Но это не имеет stl-реализации. Есть некоторые реализации для этого типа поведения (я сам попробовал один раз, но это немного беспорядок), но я не знаю, есть ли что-нибудь в надбавке.

1 голос
/ 06 апреля 2020

Как говорит ссылка, предоставленная Вирсавией, проблема в том, что std::vector<T> действительно std::vector<T, std::allocator<T>>. До C ++ 20 std::allocator<T>::address() имел две перегрузки, одна из которых принимает T&, а другая - T const&. Проблема с T=const int должна быть очевидной. В C ++ нет такого понятия, как extra-const, поэтому обе перегрузки одинаково хороши.

...