Фиксированный размер вектора:
Почему вы используете std::vector
вместо std:array
для "фиксированного" массива?
Создает вектор размером 1. (1)
Нет, это не так. Он создает vector
, чьи size()
и capacity()
изначально равны 0, а не 1. Ваше значение siz
используется как искусственная максимальная емкость , вы все еще позволяете вектору динамически расти пока он не достигнет вашего максимума.
EXPECT_THROW(t1.add(new ClonableTestClass), MyException);
Здесь следует выбросить исключение. (3)
Правда и, что еще хуже, в результате происходит утечка объекта ClonableTestClass
. Вместо этого вам следует использовать std::unique_ptr<ClonableTestClass>
, чтобы вы всегда владели объектом и правильно его освобождали, даже если выдается исключение.
как я могу проверить, когда я достигну "max_size ()" моего вектора.
Вы уже есть. Это именно то, что делает size() >= siz
.
Или как мне вернуть значение, которое я дал в коде (1) (число между!):
ClonableHeteroStore<ClonableTestClass, fixVec<ClonableTestClass*, !!!1!!! >, MyException> t1;
Доступно только в параметре шаблона siz
. Если вы хотите, чтобы ВНЕШНИЙ код знал значение siz
, то вам необходимо предоставить к нему публичный доступ, например:
template <typename T, size_t siz>
struct fixVec : public std::vector<T>
{
const size_t max_elements_allowed;
fixVec() : max_elements_allowed(siz) {}
...
};
Или, если вы используете C ++ 11 или более позднюю версию:
template <typename T, size_t siz>
struct fixVec : public std::vector<T>
{
const size_t max_elements_allowed = siz;
...
};
Тогда вы можете сделать это:
void add(T1 *rhs)
{
if (currently < flakker.max_elements_allowed)
{
flakker.push_back(rhs);
currently++;
}
else
{
delete rhs;
throw PRED();
}
}
К вашему сведению, вам на самом деле не нужно currently
, вы можете просто использовать flakker.size()
вместо:
void add(T1 *rhs)
{
if (flakker.size() < flakker.max_elements_allowed)
{
flakker.push_back(rhs);
}
else
{
delete rhs;
throw PRED();
}
}
Тем не менее, std::vector
имеет метод capacity()
, который вы действительно ищете:
void add(T1 *rhs)
{
if (flakker.size() < flakker.capacity())
{
flakker.push_back(rhs);
}
else
{
delete rhs;
throw PRED();
}
}
Вам просто нужно предварительно выделить внутренний массив vector
заранее:
template <typename T, size_t siz>
struct fixVec : public std::vector<T>
{
fixVec() { std::vector<T>::reserve(siz); } // <-- add this!
...
};
У меня есть класс с именем ClonableHeteroStore, где у меня есть следующий код:
...
Что он должен делать: если мы не достигли максимального размера вектора, который мы дали в коде (1), он должен добавить новый элемент к вектору. В случае, если мы достигли предела, который мы дали в коде (1), должно быть исключение.
Поскольку ваш fixVec
уже обрабатывает это, вы должны просто добавить элемент безоговорочно и позволить push_back()
throw при необходимости:
void add(T1 *rhs)
{
try
{
flakker.push_back(rhs);
}
catch (...)
{
delete rhs;
throw PRED();
}
}
Лучшее решение - позволить вызывающей стороне сохранять право собственности на добавляемый объект и не освобождать эту собственность, если add()
не будет успешным. Таким образом, если выдается исключение, вызывающая сторона может правильно освободить объект и не пропустить его. Это не должно быть обязанностью add()
:
void add(T1 *rhs)
{
try
{
flakker.push_back(rhs);
}
catch (...)
{
throw PRED();
}
}
...
ClonableTestClass *obj = new ClonableTestClass;
try
{
t1.add(obj);
}
catch (...)
{
delete obj;
throw;
}
Или, если вы используете C ++ 11 или более позднюю версию:
std::unique_ptr<ClonableTestClass> obj(new ClonableTestClass);
t1.add(obj.get());
obj.release();
Или:
void add(std::unique_ptr<T1> rhs)
{
try
{
flakker.push_back(rhs.get());
rhs.release();
}
catch (...)
{
throw PRED();
}
}
...
t1.add(std::unique_ptr<ClonableTestClass>(new ClonableTestClass));
Единственный код, который можно изменить, это класс ClonableHeteroStore. Каким-то образом я должен выяснить, насколько велик мой вектор.
Если вы не можете изменить fixVec
, чтобы сделать его значение siz
общедоступным, и вы должны выяснить его siz
, то вам придется прибегнуть к некоторой хитрости шаблона, например:
template<typename T, size_t siz>
size_t get_capacity(const fixVec<T, siz> &) { return siz; }
...
void add(T1 *rhs)
{
if (flakker.size() < get_capacity(flakker))
flakker.push_back(rhs);
else
throw PRED();
}
Но именно поэтому контейнеры STL предоставляют стандартные методы size()
и capacity()
, поэтому вам не нужно прибегать к подобным приемам.
С другой стороны, ClonableHeteroStore
на самом деле не нужно знать это значение siz
для начала. Он должен просто выполнить push_back()
безоговорочно и позволить ему бросить, если необходимо.
Я много читал, что вектор динамически выделяет свой размер и т. Д. И т. Д., Но в этом случае он должен выдать исключение, если я перепрыгну через предел (1).
Вы действительно должны использовать std::array
вместо std::vector
.
Если вы должны использовать std::vector
, то вам следует подумать о написании пользовательского Allocator
для использования vector
вместо использования по умолчанию Allocator
. Пользовательский Allocator
может выдать, если его просят выделить память для слишком большого количества элементов. Тогда вы можете позволить std::vector
вести себя нормально и вообще не переопределять его push_back()
.