2015-07-31 15 views
13

Chcę mieć pewnego rodzaju std::vector, który nie może mieć więcej niż const int MAX_LENGTH elementów. Rozumiem, że nie mogę przesłonić innych niż wirtualne funkcji, które musiałbym wykonać, aby umieścić kontrolę rozmiaru we wszystkich odpowiednich funkcjach składowych (np. assign, push_back ... jest ich tak wiele). Najbardziej oczywistym sposobem na zrobienie tego jest owijanie std::vector w class, który zapewnia, że ​​żadna operacja nie zostanie przedłużona poza maksymalną długość. Ale wydaje się to nieporęczne. Czy istnieje bardziej eleganckie rozwiązanie niż klasa opakowania w celu ograniczenia rozmiarów std :: vector?Niewpuszczalny sposób na wymuszenie ograniczenia rozmiaru na std :: vector?

+0

@LuchianGrigore Nie, potrzebuję interfejsu wektorowego lub wektorowego. – helloB

+5

Jakiego zachowania oczekujesz, jeśli zostanie naruszone? Jeśli wektor ma taką pojemność, co powinien zrobić 'push_back' (lub equiv)? Zgłaszać wyjątek? Cicho odrzucić ten element? Dodaj ten element kosztem pierwszego elementu (zachowanie typu kolejki FIFO)? – CoryKramer

+0

@CoryKramer Chciałbym rzucić wyjątek i przypomnieć użytkownikowi, że złamali warunki używania tego konkretnego rodzaju wektora (wektor jest tym, który używa określonego przydziału) – helloB

Odpowiedz

14

Czy jesteś pewien, że sam wektor nie może się rozwinąć, lub że tylko konsumenci takiego wektora muszą ograniczyć rozmiar argumentów? Jeśli to drugie, to po prostu assert(arg.size() <= MAX_LENGTH) w razie potrzeby, udokumentuj to i gotowe. W przeciwnym razie czytaj dalej.

A std::vector może mieć nieograniczony rozmiar. Jeśli ograniczysz ten rozmiar, to już nie jest to std::vector. Więc nie możesz publicznie czerpać z std::vector i ograniczać rozmiaru bez łamania Liskov Substitution Principle. Klasa pochodna nadal jest wektorem, ale nie działa tak jak jeden i nie może być używana jako jedna, a taki interfejs całkowicie zmyli użytkowników, a kompilator nie wykryje poważnych błędów użytkowania. To zły pomysł.

Najlepsze, co można zrobić, to prywatnie czerpać z wektora lub mieć wektor jako element członkowski i odsłonić wszystkie interfejsy wektorowe, jednocześnie wymuszając rozmiar. Taki wektor musi być , a nie być zamienny na std::vector, chociaż oczywiście można zezwolić na jego skopiowanie lub przeniesienie do std::vector. Nadal będzie działał tak dobrze, jak wektor będzie nadal pozwalał na dostęp poprzez iteratory, itp.

Mówimy o bardzo małej klasie, a jej implementacja musi po prostu być zgodna ze standardem (lub przynajmniej the cpp reference), pozostawiasz całą prawdziwą pracę prywatnemu std::vector. Więc to nie jest przyziemne, to jedyny rozsądny sposób, aby to zrobić.

+0

Rozumiem twój punkt widzenia. Podoba mi się ten pomysł assert (arg.size() <= MAX_LENGTH), ale gdzie by to poszło, gdyby nie niestandardowa klasa opakowania? Nie mogę zmusić klientów do umieszczania ich przed każdym telefonem, więc czy istnieje sposób, aby to zrobić automatycznie? – helloB

+0

Nie używałbyś assert, gdybyś chciał podnieść konkretny wyjątek, użyłbyś go do zawieszenia programu, ponieważ popełniłeś błąd –

+0

@helloB Klienci definitywnie mogą je umieścić, jeśli naprawdę nie mogą zaakceptować wektora za duży. Po to są twierdzenia. W przeciwnym razie wydaje się, że masz problem. Wektor nie dba o jego rozmiar, teraz klienci też go nie interesują, więc dlaczego pytanie? Jeśli klienci się tym przejmują, muszą sprawdzić lub zaakceptować ograniczoną wielkość klasy wektorowej, a nie "std :: vector". Jeśli klienci nie przejmują się, dlaczego? –

2

Od C++ 11, niestandardowe alokatory mogą mieć stan (poprzednio w C++ 11, niestandardowe alokatory musiały być bezstanowe). Każdy kontener C++, który pobiera niestandardowy alokator, przechowuje jego instancję.

Twój alokator może następnie sprawdzić, czy już wypełnił żądanie maksymalnego przydziału i rzucić coś innego.

+0

Działa to tylko wtedy, gdy posiadam indywidualną instancję przydzielania dla każdego wektora nr? Albo musiałbym mieć dość dużo zarejestrowanego stanu w alokatorze, śledząc każdy wektor, który mu przydzielił. – helloB

+0

@helloB: Tak. Każdy wektor ma własną instancję alokatora (drugie zdanie pierwszego akapitu). – jxh

+0

To niekoniecznie musi być. Widziałem podzielniki podzielone między kontenerami. – helloB

2
#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; 
} 
Powiązane problemy