Reputation: 40145
As the tile says, is there anyway that I can declare a vector in C++ 14 and limit the max number of entries it can hold?
Upvotes: 6
Views: 188
Reputation: 117937
One possible solution would be to create your own Allocator. std::allocator
is stateless, but yours could implement the max_size()
member function which should return the value of a member variable that carries the max number of elements.
An example that will work from C++11 up until at least C++20:
template<class T>
struct limited_allocator : public std::allocator<T> {
using value_type = typename std::allocator<T>::value_type;
using size_type = typename std::allocator<T>::size_type;
using difference_type = std::ptrdiff_t;
using propagate_on_container_move_assignment = std::true_type;
using is_always_equal = std::false_type; // not needed since C++23
#if __cplusplus < 201703L
using pointer = typename std::allocator<T>::pointer;
using const_pointer = typename std::allocator<T>::const_pointer;
using reference = typename std::allocator<T>::reference;
using const_reference = typename std::allocator<T>::const_reference;
template<class U> struct rebind {
typedef limited_allocator<U> other;
};
#endif
// No default constructor - it needs a limit:
constexpr limited_allocator(size_type max_elements) noexcept :
m_max_elements(max_elements) {}
constexpr limited_allocator( const limited_allocator& other ) noexcept = default;
template< class U >
constexpr limited_allocator( const limited_allocator<U>& other ) noexcept :
m_max_elements(other.m_max_elements) {}
// Implementing this is what enforces the limit:
size_type max_size() const noexcept { return m_max_elements; }
private:
size_type m_max_elements;
};
Since this allocator isn't stateless, you'd better implement the non-member comparison functions too:
template< class T1, class T2 >
constexpr bool operator==(const limited_allocator<T1>& lhs,
const limited_allocator<T2>& rhs ) noexcept {
return &lhs == &rhs;
}
template< class T1, class T2 >
constexpr bool operator!=(const limited_allocator<T1>& lhs,
const limited_allocator<T2>& rhs ) noexcept {
return &lhs != &rhs;
}
A usage example, in which the vector
is allowed to keep 1
element only:
int main() {
std::vector<int, limited_allocator<int>> vec(limited_allocator<int>(1));
// ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
try {
vec.push_back(1); // one element
vec.pop_back(); // zero again
vec.push_back(2); // one again
vec.push_back(3); // here it'll throw
}
catch(const std::length_error& ex) {
std::cout << "length_error: " << ex.what() << '\n';
}
catch(const std::bad_array_new_length& ex) {
std::cout << "bad_array_new_length: " << ex.what() << '\n';
}
catch(const std::bad_alloc& ex) {
std::cout << "bad_alloc: " << ex.what() << '\n';
}
}
Possible output:
length_error: vector::_M_realloc_insert
Upvotes: 8