std::basic_string
最大サイズが任意のカスタムアロケータを渡すことができます。これで十分です。おそらくこのようなもの:
template <class T>
class my_allocator {
public:
typedef T value_type;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
pointer address(reference r) const { return &r; }
const_pointer address(const_reference r) const { return &r; }
my_allocator() throw() {}
template <class U>
my_allocator(const my_allocator<U>&) throw() {}
~my_allocator() throw() {}
pointer allocate(size_type n, void * = 0) {
// fail if we try to allocate too much
if((n * sizeof(T))> max_size()) { throw std::bad_alloc(); }
return static_cast<T *>(::operator new(n * sizeof(T)));
}
void deallocate(pointer p, size_type) {
return ::operator delete(p);
}
void construct(pointer p, const T& val) { new(p) T(val); }
void destroy(pointer p) { p->~T(); }
// max out at about 64k
size_type max_size() const throw() { return 0xffff; }
template <class U>
struct rebind { typedef my_allocator<U> other; };
template <class U>
my_allocator& operator=(const my_allocator<U> &rhs) {
(void)rhs;
return *this;
}
};
次に、おそらくこれを行うことができます:
typedef std::basic_string<char, std::char_traits<char>, my_allocator<char> > limited_string;
編集:これが期待どおりに機能することを確認するためのテストを実行しました。次のコードはそれをテストします。
int main() {
limited_string s;
s = "AAAA";
s += s;
s += s;
s += s;
s += s;
s += s;
s += s;
s += s; // 512 chars...
s += s;
s += s;
s += s;
s += s;
s += s;
s += s; // 32768 chars...
s += s; // this will throw std::bad_alloc
std::cout << s.max_size() << std::endl;
std::cout << s.size() << std::endl;
}
その最後s += s
はそれを上に置き、std::bad_alloc
例外を引き起こします(私の制限は64kにちょうど足りないので)。残念ながら、gccのstd::basic_string::max_size()
実装は、使用するアロケータに基づいて結果を生成しないため、さらに多くを割り当てることができると主張します。(これがバグかどうかはわかりません...)。
しかし、これにより、簡単な方法で文字列のサイズに厳しい制限を課すことができます。最大サイズをテンプレートパラメータにすることもできるので、アロケータのコードを1回記述するだけで済みます。