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

Неинтрузивный способ принудительного ограничения размера на std::vector?

Я хочу иметь определенный тип std::vector, который не может содержать больше элементов const int MAX_LENGTH. Я понимаю, что я не могу переопределить не виртуальные функции std::vector, которые мне нужно будет сделать, чтобы поместить проверку размера во все соответствующие функции-члены (например, assign, push_back... их так много), Самый очевидный способ сделать это - обернуть std::vector в class, который не гарантирует, что никакая операция не будет превышать максимальную длину. Но это кажется неуклюжим. Есть ли более элегантное решение, чем класс оболочки для ограничения размера std::vector?

4b9b3361

Ответ 1

Вы уверены, что сам вектор не может расти или что только потребители такого вектора должны ограничить размер аргументов? Если это последний, то просто assert(arg.size() <= MAX_LENGTH), где это необходимо, документируйте его и сделайте. В противном случае, читайте дальше.

A std::vector может иметь неограниченный размер. Если вы ограничите этот размер, это не будет std::vector. Таким образом, вы не можете публично выводить из std::vector и ограничивать размер, не нарушая Принцип замены Лискова. Полученный класс по-прежнему является вектором, но не действует как один и не может использоваться как один, и такой интерфейс полностью запутает ваших пользователей, и компилятор не поймает серьезных ошибок использования, которые будут возникать. Это плохая идея.

Лучшее, что вы можете сделать, - это частное извлечение из вектора или наличие вектора в качестве члена, а также отображение всех векторных интерфейсов при обеспечении размера. Такой вектор не должен быть конвертирован в std::vector, хотя, очевидно, вы можете разрешить его копировать или перемещать в std::vector. Он по-прежнему будет работать так же хорошо, как и вектор, будет по-прежнему разрешать доступ через итераторы и т.д.

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

Ответ 2

Так как С++ 11, пользовательским распределителям разрешено иметь состояние (ранее С++ 11, пользовательские распределители должны были быть без гражданства). Каждый контейнер С++, который использует специализированный распределитель, хранит его экземпляр.

Затем ваш распределитель может определить, выполнил ли он уже запрос на максимальный выделение, и выбросил иначе.

Ответ 3

#include <vector>
#include <string>
using namespace std;

template <typename T, typename A>

void add_or_throw(std::vector<T,A> &vec, int max, T value)
{
    if (vec.size() < max)
    {
        vec.push_back(value);
    }else{
        throw length_error("vecor too beaucoup");
    }
}

int main() {
    std::vector<std::string> v;
    add_or_throw(v, 2, string("hi"));
    add_or_throw(v, 2, string("there"));
    add_or_throw(v, 2, string("man!"));

    return 0;
}