使用c风格数组作为STL字符串操作的后端



我正在编写一个库来读取一些特定的文件格式。使用内存映射文件(boost::interprocess模板)读取文件。在这些文件上,我必须用std::regex做一些搜索。为了避免不必要的复制,我想直接使用内存映射文件(作为c风格的字符数组)。

经过一番研究,我提出了以下两种方法:

  • 使用streambuf对象的pubsetbuf方法
  • 使用char*指针作为迭代器

,但是由于第一种方法的实现对于STL供应商来说是可选的,所以我坚持使用第二种方法。由于std::string::iterator的构造函数被声明为私有,并且整个迭代器的实现似乎也是特定于供应商的。我写了自己的迭代器:

template<typename T>
class PointerIterator: std::iterator<std::input_iterator_tag, T> {
public:
    PointerIterator(T* first, std::size_t count): first_(first), last_(first + count) {}
    PointerIterator(T* first, T* last): first_(first), last_(last) {}
    class iterator {
    public:
        iterator(T* p): ptr_(p) {}
        iterator(const iterator& it): ptr_(it.ptr_) {}
        iterator& operator++() {
            ++ptr_;
            return *this;
        }
        iterator operator++(int) {
            iterator temp(*this);
            ++ptr_;
            return temp;
        }
        bool operator==(const iterator& it) { return ptr_ == it.ptr_; }
        bool operator!=(const iterator& it) { return ptr_ != it.ptr_; }
        T& operator*() { return *ptr_; }
    private:
        T* ptr_;
    };    
    iterator begin() {
        return iterator(first_);
    }
    iterator end() {
        return iterator(last_);
    }
private:
    T* first_;
    T* last_;
};

迭代器可以工作,但是对于std::regex_search方法(或其他与char相关的STL方法),它必须与STL迭代器的类型相同。

是否有一些通用的方法将我的迭代器转换为STL的(可移植到STL实现上),或者用另一种我没有提到的方法实现整个事情?

编辑:

使用std::regex_search:

的源代码
std::regex re(...);
boost::interprocess::mapped_region region(...);
char* first = static_cast<char*>(region.get_address());
char* last = first + 5000;
// ...
PointerIterator<char> wrapper(first, last);
std::smatch match;
while (std::regex_search(wrapper.begin(), wrapper.end(), match, re)) {  // Error: No matching function call to 'regex_search'
     // do something
}

谢谢

std::smatch的定义是std::match_results的专门化。这个特化使用string::const_iterator作为传递给std::match_results的模板实参中的迭代器类型。这要求传递给std::regex_search的begin和end参数也必须是string::const_iterator类型的。

在c++中,指针满足双向迭代器的要求,没有必要将它们包装在迭代器类中。如果需要搜索由char指针指向的缓冲区,可以使用std::cmatchstd::match_results并显式指定迭代器类型。在下面的两个示例中,我保留了使用PointerIterator来提供直接应用于当前代码库的解决方案。我还包含了一个独立的示例,如果您想要消除自定义迭代器类的使用,您可以引用它。
PointerIterator<char> wrapper(first, last);
std::cmatch match; // <<--
while (std::regex_search(wrapper.begin(), wrapper.end(), match, re))
{
    // do something
}

…使用std::match_results代替。

PointerIterator<char> wrapper(first, last);
std::match_results<const char*> match; // <<--
while (std::regex_search(wrapper.begin(), wrapper.end(), match, re))
{
    // do something
}

下面是一个独立的例子,应该提供一些成文的澄清。它基于cppreference.com上的示例,并使用const char*而不是std::string作为搜索目标。

#include <regex>
#include <iostream>
int main()
{
    const char *haystack = "Roses are #ff0000";
    const int size = strlen(haystack);
    std::regex pattern(
        "#([a-f0-9]{2})"
        "([a-f0-9]{2})"
        "([a-f0-9]{2})");
    std::cmatch results;
    std::regex_search(haystack, haystack + size, results, pattern);
    for (size_t i = 0; i < results.size(); ++i) {
        std::csub_match  sub_match = results[i];
        std::string sub_match_str = sub_match.str();
        std::cout << i << ": " << sub_match_str << 'n';
    }  
}

生成如下输出:

0: # ff0000
1: ff
2: 00
03:00

最新更新