简体   繁体   English

比较使用不同分配器的STL字符串

[英]Comparing STL strings that use different allocators

I'd like to compare STL strings that are allocated with different allocators , eg an ordinary std::string with a string using a custom STL allocator . 我想比较使用不同分配器分配的STL字符串,例如使用自定义STL分配器的普通std::string和字符串。 Unfortunately, it seems that usual operator==() doesn't work in this case: 不幸的是,似乎通常的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
   ...

In particular, MSVC10 (VS2010 SP1) emits the following error message: 特别是,MSVC10(VS2010 SP1)发出以下错误消息:

error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::string' (or there is no acceptable conversion) 错误C2678:二进制'==':找不到哪个运算符带有'std :: string'类型的左操作数(或者没有可接受的转换)

So, a lower-level (less readable) code like this: 所以,这样的低级 (不太可读)代码:

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

should be used. 应该使用。

(This is also particularly annoying in cases where eg there are std::vector 's of differently-allocated strings, where the usual simple v[i] == w[j] syntax can't be used.) (在例如存在不同分配的字符串的std::vector的情况下,这也是特别烦人的,其中不能使用通常的简单v[i] == w[j]语法。)

This doesn't seem very good to me, since a custom allocator changes the way string memory is requested, but the interface of a string class (including comparison with operator==() ) is independent from the particular way a string allocates its memory. 这对我来说似乎不太好,因为自定义分配器改变了请求字符串内存的方式,但字符串类的接口 (包括与operator==()比较)独立于字符串分配其内存的特定方式。

Is there something I am missing here? 这里有什么我想念的吗? Is it possible to keep the C++ high-level interface and operator overloads in this case? 在这种情况下,是否可以保持C ++高级接口和运算符重载?

Use std::lexicographical_compare for less-than comparison: 使用std::lexicographical_compare进行小于比较:

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

For equality comparison you can use std::equal : 对于相等比较,您可以使用std::equal

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

Alternatively, you can just fall back on strcmp (or actually memcmp , since that has the correct semantics; remember that the C++ string is more general than a C string), as you suggested, which can potentially employ some lower-level magic like comparing an entire machine word at a time (though the above algorithm may also be specialized thus). 或者,您可以回退到strcmp (或实际上是memcmp ,因为它具有正确的语义;请记住,C ++字符串比C字符串更通用),正如您所建议的那样,这可能会使用一些较低级别的魔法,如比较一次整个机器字(尽管上述算法因此也可以是专用的)。 Measure and compare, I'd say. 我会说,测量和比较。 For short strings, the standard library algorithms are at least nicely self-descriptive. 对于短字符串,标准库算法至少具有很好的自描述性。


Based on @Dietmar's idea below, you could wrap those functions into a templated overload: 根据@ 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());
}

Usage example: 用法示例:

#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;
}

In fact, you could define such an overload for most standard containers. 实际上,您可以为大多数标准容器定义这样的重载。 You could even template it on a template, but that would be extreme. 你甚至可以在模板上模板化,但那将是极端的。

The standard only define operators using homogenous string types, ie, 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, ie, 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? 也就是说,还有另一个不支持混合类型比较的潜在原因:如果operator==()确实成为两个值之间的比较,就像分配器不同的情况那样,它可能会引发更广泛的值平等定义:应该支持std::vector<T>() == std::deque<T>吗? 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. 当然,分配器是std::basic_string<C, T, A>的非显着属性,这可能是忽略它的一个很好的理由。 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. 对于仅在其分配器类型上不同的容器类型,支持运算符(这可能扩展到除operator==()之外的其他运算operator==()可能是合理的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM