Мне нужен контейнер C++ со следующими требованиями:
- Контейнер может хранить некопируемые И неподвижные объекты в непрерывной памяти. Для
std::vector
объект должен быть либо копируемым, либо перемещаемым. capacity
контейнера известен во время построения во время выполнения и фиксируется до уничтожения. При построении выделяется весь необходимый объем памяти. Дляboost::static_vector
емкость известна во время компиляции.- Размер контейнера может увеличиваться со временем, когда в контейнере становится
emplace_back
элемента, но никогда не должен превышатьcapacity
. - Поскольку объект нельзя копировать или перемещать, перераспределение не допускается.
Похоже, что ни в STL, ни в BOOST нет нужного мне типа контейнера. Я также много искал в этой стороне, но не нашел ответа. Итак, я реализовал один.
#include <memory>
template<class T>
class FixedCapacityVector {
private:
using StorageType = std::aligned_storage_t<sizeof(T), alignof(T)>;
static_assert(sizeof(StorageType) == sizeof(T));
public:
FixedCapacityVector(FixedCapacityVector const&) = delete;
FixedCapacityVector& operator=(FixedCapacityVector const&) = delete;
FixedCapacityVector(size_t capacity = 0):
capacity_{ capacity },
data_{ std::make_unique<StorageType[]>(capacity) }
{ }
~FixedCapacityVector()
{
for (size_t i = 0; i < size_; i++)
reinterpret_cast<T&>(data_[i]).~T();
}
template<class... Args>
T& emplace_back(Args&&... args)
{
if (size_ == capacity_)
throw std::bad_alloc{};
new (&data_[size_]) T{ std::forward<Args>(args)... };
return reinterpret_cast<T&>(data_[size_++]);
}
T& operator[](size_t i)
{ return reinterpret_cast<T&>(data_[i]); }
T const& operator[](size_t i) const
{ return reinterpret_cast<T const&>(data_[i]); }
size_t size() const { return size_; }
size_t capacity() const { return capacity_; }
T* data() { return reinterpret_cast<T*>(data_.get()); }
T const* data() const { return reinterpret_cast<T const*>(data_.get()); }
private:
size_t const capacity_;
std::unique_ptr<StorageType[]> const data_;
size_t size_{ 0 };
};
Мои вопросы:
- Зачем мне делать это вручную? Я не смог найти стандартный контейнер. А может я не там смотрел? Или потому, что то, что я пытаюсь сделать, не является обычным?
- Правильно ли реализован рукописный контейнер? Как насчет безопасности исключений, безопасности памяти и т. д.?
std::shared_ptr
, а затемstd::shared_ptr
храниться вstd::vector
? - person Eljay   schedule 26.12.2018std::vector<std::unique_ptr>
). Может быть, я не должен говорить такой часто используемый тип контейнера. - person Tony Xiang   schedule 26.12.2018std::vector
, размер которого изменен до максимально необходимого, и не отслеживать, сколько элементов фактически используется? Если этот вектор является закрытым членом вашего класса, вы можете гарантировать, что его размер никогда не изменится после инициализации, что бы ни делал пользователь вашего класса. В конце концов, даже если пользователь просит ваш класс что-тоemplace_back()
, вашему классу (или реализации его функций-членов) не нужно превращать это в вызовыemplace_back()
вектора. - person Peter   schedule 26.12.2018std::vector<T>
не будет компилироваться, еслиT
нельзя ни копировать, ни перемещать. - person Tony Xiang   schedule 26.12.2018p
— это указатель на неразрушенныйT
). Однако вам нужно быть осторожным при выборе операций над вектором, так как некоторые функции-членыstd::vector
имеют более строгие требования (например, [из памяти] векторemplace()
требует, чтобы элементы были Move Assignable, Move Insertable и Emplace Constructible — в отличие от копирования присваиваемый и копируемый). - person Peter   schedule 26.12.2018std::vector<T>
для некопируемого-неподвижногоT
. Как вы сказали, сам экземпляр может быть скомпилирован. Однако ни один из методов не может быть использован для добавления элемента в вектор. Я подумал, что можно использоватьemplace_back
, поскольку он не требует копирования или перемещения, если не требуется перераспределение. Но компилятор все еще жалуется на удаленный конструктор копирования. У вас есть идеи, как добавить элемент в вектор в этом случае? - person Tony Xiang   schedule 26.12.2018