我正在使用一个低级API,它接受char*
和数值来分别表示字符串及其长度。我的代码使用std::basic_string
并使用适当的翻译调用这些方法。不幸的是,这些方法中的许多方法接受不同大小的字符串长度(即max(unsigned char
),max(short
)等等...而且我很难编写代码以确保我的字符串实例不超过低级API规定的最大长度。
默认情况下,std::basic_string
实例的最大长度受size_t
的最大值(max(unsigned int
)或max(__int64
))的约束。有没有办法操纵std::basic_string
实现的特征和分配器实现,以便我可以指定我自己的类型来代替size_t
?通过这样做,我希望利用std::basic_string
实现中的任何现有边界检查,因此在执行翻译时我不必这样做。
我的初步调查显示,如果不编写我自己的字符串类,这是不可能的,但我希望我忽略了一些事情:)
答案 0 :(得分: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()
实现不会将结果基于您使用的分配器,因此它仍然声称能够分配更多。 (我不确定这是不是一个错误......)。
但这肯定会让你以简单的方式对字符串的大小施加硬性限制。您甚至可以将max size设置为模板参数,这样您只需要为分配器编写一次代码。
答案 1 :(得分: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
答案 2 :(得分:0)
你不能用std :: string作为父创建一个类并覆盖c_str()吗? 或者定义自己的c_str16(),c_str32()等,并在那里实现翻译?