programing

다른 할당자를 사용하는 STL 문자열 비교

nasanasas 2020. 12. 9. 08:19
반응형

다른 할당자를 사용하는 STL 문자열 비교


다른 할당 자로 할당 된 STL 문자열 , 예를 들어 사용자 지정 STL 할당자를std::string 사용하는 문자열과 일반 문자열을 비교하고 싶습니다 . 불행히도이 경우에는 평소 가 작동하지 않는 것 같습니다 .operator==()

// Custom STL allocator to allocate char's for string class
typedef MyAllocator<char> MyCharAllocator;

// Define an instance of this allocator
MyCharAllocator myAlloc;

// An STL string with custom allocator
typedef std::basic_string
<
    char, 
    std::char_traits<char>, 
    MyCharAllocator
> 
CustomAllocString;

std::string s1("Hello");
CustomAllocString s2("Hello", myAlloc);

if (s1 == s2)  // <--- ERROR: doesn't compile
   ...

특히 MSVC10 (VS2010 SP1)은 다음과 같은 오류 메시지를 표시합니다.

오류 C2678 : 바이너리 '==': 'std :: string'유형의 왼쪽 피연산자를 사용하는 연산자를 찾을 수 없습니다 (또는 허용되는 변환이 없음).

따라서 다음과 같은 하위 수준 (덜 읽기 쉬운) 코드는 다음과 같습니다.

if (strcmp(s1.c_str(), s2.c_str()) == 0)
   ...

사용되어야한다.

(이것은 또한 예를 들어 std::vector일반적인 단순 v[i] == w[j]구문을 사용할 수없는 다르게 할당 된 문자열 이있는 경우에 특히 성가시다 .)

커스텀 할당자가 문자열 메모리가 요청되는 방식을 변경하기 때문에 이것은 나에게 좋지 않은 것 같지만 문자열 클래스 인터페이스 (와 비교 포함 operator==())는 문자열이 메모리를 할당하는 특정 방식 독립적입니다.

내가 여기에 빠진 것이 있습니까? 이 경우 C ++ 고급 인터페이스 및 연산자 오버로드를 유지할 수 있습니까?


사용 std::lexicographical_compare비교보다 작음을 위해 :

bool const lt = std::lexicographical_compare(s1.begin(), s1.end(),
                                             s2.begin(), s2.end());

동등성 비교를 위해 std::equal다음 을 사용할 수 있습니다 .

bool const e = s1.length() == s2.length() &&
               std::equal(s1.begin(), s1.end(), s2.begin());

또는 제안한대로 strcmp(또는 실제로 memcmp는 올바른 의미를 가지고 있기 때문에, C ++ 문자열이 C 문자열보다 더 일반적이라는 것을 기억하십시오) 전체를 비교하는 것과 같은 낮은 수준의 마법을 잠재적으로 사용할 수 있습니다. 한 번에 기계어 (위의 알고리즘도 특수화 될 수 있음). 측정하고 비교합니다. 짧은 문자열의 경우 표준 라이브러리 알고리즘은 최소한 자체 설명 적입니다.


아래 @Dietmar의 아이디어에 따라 이러한 함수를 템플릿 오버로드로 래핑 할 수 있습니다.

#include <string>
#include <algorithm>

template <typename TChar,
          typename TTraits1, typename TAlloc1,
          typename TTraits2, typename TAlloc2>
bool operator==(std::basic_string<TChar, TTraits1, TAlloc1> const & s1,
                std::basic_string<TChar, TTraits2, TAlloc2> const & s2)
{
    return s1.length() == s2.length() &&
           std::equal(s1.begin(), s1.end(), s2.begin());
}

사용 예 :

#include <ext/malloc_allocator.h>
int main()
{
    std::string a("hello");
    std::basic_string<char, std::char_traits<char>, __gnu_cxx::malloc_allocator<char>> b("hello");
    return a == b;
}

실제로 대부분의 표준 컨테이너에 대해 이러한 오버로드를 정의 할 수 있습니다. 템플릿에 템플릿을 적용 할 수도 있지만 그것은 극단적 일 것입니다.


The standard only define operators using homogenous string types, i.e., all the template arguments need to match. However, you can define a suitable equality operator in the namespace where the allocator is defined: argument dependent look-up will find it there. If you choose to implement your own assignment operator, it would look something like this:

bool operator== (std::string const& s0,
                 std::basic_string<char, std::char_traits<char>, MyCharAllocator> const& s1) {
    return s0.size() == s1.size() && std::equal(s0.begin(), s0.end(), s1.begin()).first;
}

(plus a few other overloads). Taking this to next level, it may even be reasonable to define versions the various relational operators in terms of the container requirements and not restricting the template arguments:

namespace my_alloc {
    template <typename T> class allocator { ... };
    template <typename T0, typename T1>
    bool operator== (T0 const& c0, T1 const& c1) {
        return c0.size() == c1.size() && std::equal(c0.begin(), c0.end(), c1.end);
    }
    ...
}

Obviously, the operators can be restricted to specific container types, differing only in their allocator template parameters.

With respect to why the standard doesn't define mixed type comparisons, the main reason behind not supporting mixed type comparison is probably that you actually don't want to mix allocators in your program in the first place! That is, if you need to use an allocator, you'd use an allocator type which encapsulates a dynamically polymorphic allocation policy and always use the resulting allocator type. The reasoning for this would be that otherwise you'd get either incompatible interface or you would need to make everything a template, i.e., you want to retain some level of vocabulary types being used. Of course, with using even just one additional allocator type, you'd have two vocabulary string types: the default instantiation and the instantiation for your special allocation.

That said, there is another potential reason to not support mixed type comparison: If operator==() really becomes a comparison between two values, as is the case if the allocators differ, it may give raise to a much broader definition of value equality: should std::vector<T>() == std::deque<T> be supported? If not, why would comparison between strings with different allocators be special? Of course, the allocator is a non-salient attribute of std::basic_string<C, T, A> which could be a good reason to ignore it. I'm not sure if mixed type comparison should be supported. It may be reasonable to support operators (this probably extends to other operators than operator==()) for container types differing only in their allocator type.

참고URL : https://stackoverflow.com/questions/12805771/comparing-stl-strings-that-use-different-allocators

반응형