【问题标题】:Using C-style arrays as backend for STL string operations使用 C 风格的数组作为 STL 字符串操作的后端
【发布时间】:2013-06-02 19:53:10
【问题描述】:

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

经过一段时间的研究,我想出了以下两种方法:

  • 使用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 方法(或其他与字符相关的 STL 方法)一起使用,它必须与 STL 迭代器的类型相同。

是否有一些通用的方法可以将我的迭代器转换为 STL 迭代器(可移植于 STL 实现)或使用我没有提到的另一种方法来实现整个 thng?

编辑:

来源使用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::regex_search 方法一起使用 [...] 它必须与 STL 迭代器的类型相同" 您能详细说明一下吗?标准库函数大多是generic,接受满足迭代器要求的任何类型。此外,还有一个regex_search overload 接受char const*(作为干草堆)。
  • 为什么不能直接使用char* 指针作为迭代器?
  • @DyP 我正要问同样的事情。由于指针满足双向迭代器的要求,所以问题必须出在regex_search 的使用上,并且似乎没有必要将它们包装在一个交互器类中。
  • @DyP 文件中的字符串不是以零结尾的,我无法在不复制字符串的情况下添加“\0”。 regex_search 的问题是没有重载版本接受我的迭代器,而且我没有运气在我的 STL 实现中找到正确的类型(LLVM Compiler 4.2 在 OS X 上随 Xcode 一起提供)
  • 您不需要将指针包装在一个类中,因为指针满足std::regex_search 的所有迭代器要求。只需将您的第一个和最后一个指针作为 beginend 参数传递。

标签: c++ regex string stl


【解决方案1】:

std::smatch 的定义是std::match_results 的特化。此特化使用string::const_iterator 作为传递给std::match_results 的模板参数中的迭代器类型。这要求传递给std::regex_search 的开始和结束参数也是string::const_iterator 类型。

在 C++ 中,指针满足双向迭代器的要求,没有必要将它们包装在迭代器类中。如果您需要搜索char 指针指向的缓冲区,您可以使用std::cmatch 或使用std::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
3:00

【讨论】:

  • 谢谢。它奏效了,不太担心smatch,因为我在其他项目中就是这样使用它的。现在我也得到了没有任何迭代器对象的 David 版本 - 只是带有指针。了解所有 STL 确实是一项终身任务。
猜你喜欢
  • 2011-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-04
  • 2012-03-25
  • 1970-01-01
  • 2018-04-02
  • 2015-01-19
相关资源
最近更新 更多