std::basic_string を利用して長さ制限のある文字列を実装できますか?
質問
私は、 char*
文字列とその長さをそれぞれ表す数値。私のコードは使用します std::basic_string
そして、適切な変換を使用してこれらのメソッドを呼び出します。残念ながら、これらのメソッドの多くは、さまざまなサイズの文字列長を受け入れます (つまり、最大(unsigned char
)、最大(short
) など...) で、文字列インスタンスが低レベル API で規定されている最大長を超えないようにするためのコードの作成に行き詰まっています。
デフォルトでは、 std::basic_string
インスタンスは最大値によって制限されます size_t
(最大(unsigned int
) または max(__int64
))。のトレイトとアロケーターの実装を操作する方法はありますか? std::basic_string
の代わりに使用する独自の型を指定できるように実装します。 size_t
?そうすることで、既存の境界チェックを利用できるようにしたいと考えています。 std::basic_string
実装されているため、翻訳を実行するときにそうする必要はありません。
私の最初の調査では、独自の文字列クラスを作成しない限りこれは不可能であることが示唆されていますが、何かを見落としていることを願っています:)
解決
カスタム アロケータを渡すことができます 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 回記述するだけで済みます。
他のヒント
私は彼のソリューションについてエヴァンテランに同意します。これは、これ以上ちょうど彼の解決策の変形例である:
template <typename Type, typename std::allocator<Type>::size_type maxSize>
struct myalloc : std::allocator<Type>
{
// hide std::allocator[ max_size() & allocate(...) ]
std::allocator<Type>::size_type max_size() const throw()
{
return maxSize;
}
std::allocator<Type>::pointer allocate
(std::allocator<Type>::size_type n, void * = 0)
{
// fail if we try to allocate too much
if((n * sizeof(Type))> max_size()) { throw std::bad_alloc(); }
return static_cast<Type *>(::operator new(n * sizeof(Type)));
}
};
あなたはmyalloc
ですべての多型を使用すべきではありません注意してください。だから、これは悲惨です。
// std::allocator doesn't have a virtual destructor
std::allocator<char>* alloc = new myalloc<char>;
それは別のタイプであれば、それはケースを以下に安全であるように、あなたはそれを使用します:
myalloc<char, 1024> alloc; // max size == 1024
あなたは(親とオーバーライドc_strなどのstd ::文字列を持つクラスを作成することはできませんか)? それともなど、独自のc_str16()、c_str32()を定義し、翻訳を実装がありますか?