2009-10-19 10 views
6

char*を受け入れる低レベルのAPIと、文字列とその長さを表す数値を使用しています。私のコードはstd::basic_stringを使用し、これらのメソッドを適切な変換で呼び出します。残念ながら、これらのメソッドの多くはさまざまなサイズの文字列の長さを受け入れます(max(unsigned char)、max(short)など)...そして、文字列のインスタンスが指定された最大長を超えないことを確認するコードが書かれています低レベルのAPIによって。デフォルトでstd :: basic_stringを利用して長さ制限のある文字列を実装できますか?

は、std::basic_stringインスタンスの最大長はsize_tの最大値(MAX(unsigned intいずれか)またはMAX(__int64))によって結合されています。 size_tの代わりに私自身の型を指定できるように、std::basic_string実装の特性とアロケータの実装を操作する方法はありますか?そうすることで、std::basic_string実装内の既存の境界チェックを活用したいので、翻訳を実行するときにそうする必要はありません。

私の最初の調査は、これは私自身の文字列クラスを記述せずには不可能であることを示唆しているが、私は親として

答えて

5

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; 

EDIT:私は予想通り、これが動作することを確認するテストをやったし。次のコードはそれをテストします。

s += sは(私の限界は64Kのちょうど短いため)、トップの上に置くと std::bad_alloc例外が発生します続く
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; 
} 

。残念ながら、gccのstd::basic_string::max_size()実装は、使用しているアロケータにその結果を基づいていないため、さらに割り当てることができると主張します。 (これはバグかどうかは分かりませんが...)。

しかし、これは間違いなく簡単な方法で文字列のサイズに厳しい制限を課すことを可能にします。最大サイズをテンプレートパラメータにして、アロケータのコードを一度書くだけで済むようにすることもできます。

+1

intテンプレートパラメータを追加し、max_size()にNを返します。次に、typedef std :: basic_string 、my_allocator > my256stringを実行できます。 – jmucchiello

+0

私はテンプレート引数として 'size_type'を公開することは有益だろうと思っています。なぜなら、ユーザーは自由に任意の' size_type'が与えられた文字列インスタンスに最適であるように選択することができます。次に、部分テンプレートの特殊化は、この型を 'basic_string'で素敵にするのに役立ちます。 –

0

はあなたがSTDを持つクラスを作成することはできません:)何か::文字列を見落とししていることを願っていますoverride c_str()? 独自のc_str16()、c_str32()などを定義し、そこに変換を実装しますか?

+2

(仮想メソッドはありません)。これはお勧めできません。 –

4

私は彼のソリューションについてEvan Teranに同意します。これは、これ以上彼のソリューションのほんの変形例である:

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 
+0

さて、私はちょうど最大サイズをテンプレートパラメータにすることを考えました。残念ながら、私はあなたのソリューションがそのまま動作するとは思わない。 (少なくともgccの)文字列の実装は、アロケータの最大サイズの最大サイズに基づいていないためです。だから、 'max_size'バイト以上要求した場合、' allocate(...) 'throwを行わなければなりませんでした。 –

+0

@エヴァンあなたの解決策はいいです、あなたは私の+1 btwを得ました。あなたが明らかにしたように、 'allocate'のためのコードを追加します:) – AraK

関連する問題