6

char*文字列とその長さをそれぞれ表すためにと数値を受け入れる低レベルのAPIを使用しています。私のコードはstd::basic_string、適切な変換を使用してこれらのメソッドを使用および呼び出します。残念ながら、これらのメソッドの多くはさまざまなサイズの文字列の長さ(つまり、max(unsigned char)、max(short)など)を受け入れ、文字列インスタンスが低レベルのAPI。

デフォルトでは、std::basic_stringインスタンスの最大長は(max()またはmax())の最大値によって制限さsize_tunsigned intます__int64。実装の特性とアロケータ実装を操作してstd::basic_string、代わりに使用する独自のタイプを指定できるようにする方法はありますsize_tか?そうすることで、実装内の既存の境界チェックを活用したいと考えているstd::basic_stringので、変換を実行するときにそうする必要はありません。

私の最初の調査では、これは私自身の文字列クラスを書かなければ不可能であることが示唆されていますが、私は何かを見落としていることを望んでいます:)

4

3 に答える 3

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;

編集:これが期待どおりに機能することを確認するためのテストを実行しました。次のコードはそれをテストします。

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回記述するだけで済みます。

于 2009-10-19T23:33:29.450 に答える
4

私は彼の解決策についてエヴァン・テランに同意します。これは彼のソリューションの単なる修正であり、もはやありません。

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
于 2009-10-19T23:49:41.383 に答える
0

std :: stringを親としてクラスを作成し、c_str()をオーバーライドすることはできませんか?または、独自のc_str16()、c_str32()などを定義し、そこで変換を実装しますか?

于 2009-10-19T23:18:42.070 に答える