代码之家  ›  专栏  ›  技术社区  ›  Steve Guidi

可以利用std::basic_字符串来实现具有长度限制的字符串吗?

  •  6
  • Steve Guidi  · 技术社区  · 15 年前

    我正在使用接受 char* 和分别表示字符串及其长度的数值。我的代码使用 std::basic_string 并通过适当的翻译调用这些方法。不幸的是,这些方法中的许多都接受不同大小的字符串长度(即max( unsigned char (max) short )等等…)我一直在写代码,以确保我的字符串实例不会超过低级API规定的最大长度。

    默认情况下, std::基本_字符串 实例的最大值为 size_t (马克斯) unsigned int 或最大值(或最大值) __int64 )是否有一种方法可以操纵 std::基本_字符串 实现,以便我可以指定自己的类型来代替 西泽特 ?通过这样做,我希望利用 std::基本_字符串 实现,所以在执行翻译时不必这样做。

    我最初的调查表明,如果不编写自己的字符串类,这是不可能的,但我希望我忽略了一些东西:)

    3 回复  |  直到 15 年前
        1
  •  5
  •   Evan Teran    15 年前

    您可以将自定义分配器传递给 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() 实现的结果并不基于您使用的分配器,因此它仍然声称能够分配更多的分配器。(我不确定这是不是bug…)。

    但这肯定会让你以一种简单的方式对字符串的大小施加严格的限制。甚至可以将max-size设置为模板参数,因此只需为分配器编写一次代码。

        2
  •  4
  •   Khaled Alshaya    15 年前

    我同意埃文泰兰的解决方案。这只是对他的解决方案的修改,不再是:

    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
    
        3
  •  0
  •   Zepplock    15 年前

    不能用std::string作为父级并重写c_str()创建一个类吗? 或者定义自己的c_str16()、c_str32()等并在那里实现翻译?