一个杠杆的std :: basic_string的可以实现具有长度限制的字符串?(Can one l

2019-08-21 03:25发布

我与一个低级别的API,它接受一个工作char*和数值来表示一个字符串,它的长度,分别。 我的代码使用std::basic_string并调用这些方法与合适的翻译。 不幸的是,许多这些方法接受不同大小的字符串长度(即最大( unsigned char ),MAX( short ),等...),我被卡住编写代码,以确保我的字符串情况下不超过最大长度由低级API规定。

缺省情况下,最大长度std::basic_string实例是通过的最大值结合size_t (或者最大值( unsigned int )或最大( __int64 ))。 有没有一种方法来操作的特点和分配器实现std::basic_string实施,使我可以自己指定类型代替使用size_t ? 通过这样做,我希望能充分利用内的任何现有边界检查std::basic_string实现,因此我没有执行转换时这样做。

我的初步调查表明,这是不可能没有写我自己的串类,但我希望我忽略了一些:)

Answer 1:

你可以通过自定义分配器来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()实现不立足于使用分配器的结果,所以它仍然声称能够分配更多。 (我不知道这是否是一个错误或不...)。

但是,这肯定会允许你强加给字符串的大小硬限制在一个简单的方法。 你甚至可以使最大尺寸模板参数,所以你只需要一次写的分配器代码。



Answer 2:

我与埃文特兰同意他的解决方案。 这仅仅是他的解决方案的修改没有更多:

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


Answer 3:

你能不能创建一个的std ::类字符串作为家长和覆盖c_str()? 可以定义自己的c_str16(),c_str32()等,并实现翻译呢?



文章来源: Can one leverage std::basic_string to implement a string having a length limitation?