2009-10-19 7 views
6

char* 및 문자열과 길이를 나타내는 숫자 값을 허용하는 저수준 API로 작업하고 있습니다. 내 코드는 std::basic_string을 사용하고 적절한 번역으로이 메소드를 호출합니다. 불행하게도이 방법들 중 많은 것들은 다양한 크기의 문자열 길이를 허용합니다 (예 : max (unsigned char), max (short) ...). 그리고 문자열 인스턴스가 규정 된 최대 길이를 초과하지 않도록 코드를 작성하고 있습니다. 낮은 수준의 API로std :: basic_string을 사용하여 길이 제한이있는 문자열을 구현할 수 있습니까?

는 기본적으로 std::basic_string 인스턴스의 최대 길이의 최대 값에 의해 결합된다 size_t (중 최대 (unsigned int) 또는 최대 (__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; 

편집 : 난 그냥 예상대로이 작동하는지 확인하는 테스트를 수행했습니다. 다음 코드는이를 테스트합니다.

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 += sstd::bad_alloc 예외를 맨 위에 넣고 일으킬 것이다, (내 한계는 64K의 단지 짧기 때문에). 불행히도 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

당신이 표준으로 클래스를 만들 수 없습니다 : 뭔가 : 문자열을 간과하고 있음을 바라고 있어요 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 점을 얻었습니다. 나는 당신이 명확하게했던 것처럼'allocate'를 위해 더 많은 코드를 추가 할 것입니다. :) – AraK

관련 문제