mardi 10 novembre 2020

Is StringPiece conflict with the string rvalue reference?

I have seen the StringPiece class in some open source projects, say muduo network library and pcre. The implement StringPiece class is as follows:

// You can use StringPiece as a function or method parameter. A StringPiece
// parameter can receive a double-quoted std::string literal argument, a “const
// char*” argument, a std::string argument, or a StringPiece argument with no
// data copying. Systematic use of StringPiece for arguments reduces data
// copies and strlen() calls.
class StringPiece {
 public:
  StringPiece() : ptr_(nullptr), length_(0) {}
  StringPiece(const char* str) : ptr_(str), length_(strlen(str)) {}
  StringPiece(const unsigned char* str)
      : ptr_(reinterpret_cast<const char*>(str)), length_(strlen(ptr_)) {}
  StringPiece(const std::string& str)
      : ptr_(str.c_str()), length_(str.size()) {}
  StringPiece(const char* offset, int len) : ptr_(offset), length_(len) {}
  const char* data() const { return ptr_; }
  size_t size() const { return length_; }
  bool empty() const { return length_ == 0; }
  const char* begin() const { return ptr_; }
  const char* end() const { return ptr_ + length_; }

  void clear() {
    ptr_ = nullptr;
    length_ = 0;
  }
  void set(const char* buf, size_t len) {
    ptr_ = buf;
    length_ = len;
  }
  void set(const char* buf) {
    ptr_ = buf;
    length_ = strlen(ptr_);
  }
  void set(const void* buf) {
    ptr_ = static_cast<const char*>(buf);
    length_ = strlen(ptr_);
  }
  void remove_prefix(size_t n) {
    assert(n < length_);
    ptr_ += n;
    length_ -= n;
  }
  void remove_suffix(size_t n) {
    assert(n < length_);
    length_ -= n;
  }
  char operator[](size_t i) const { return ptr_[i]; }

  bool operator==(const StringPiece& str) const {
    return ((str.length_ == length_) && (memcmp(ptr_, str.ptr_, length_) == 0));
  }

  bool operator!=(const StringPiece& str) const { return !(*this == str); }

  std::string as_string() const { return std::string(ptr_, length_); }

  bool start_with(const StringPiece& str) const {
    return (length_ >= str.length_) &&
           (0 == memcmp(ptr_, str.ptr_, str.length_));
  }

#define STRINGPIECE_BINARY_PREDICATE(cmp, auxcmp)                              \
  bool operator cmp(const StringPiece& str) const {                            \
    int r =                                                                    \
        memcmp(ptr_, str.ptr_, length_ < str.length_ ? length_ : str.length_); \
    return ((r auxcmp 0)) || ((0 == r) && (length_ cmp str.length_));          \
  }
  STRINGPIECE_BINARY_PREDICATE(<, <)
  STRINGPIECE_BINARY_PREDICATE(<=, <)
  STRINGPIECE_BINARY_PREDICATE(>, >)
  STRINGPIECE_BINARY_PREDICATE(>=, >)
#undef STRINGPIECE_BINARY_PREDICATE
  int compare(const StringPiece& str) {
    int r =
        memcmp(ptr_, str.ptr_, length_ < str.length_ ? length_ : str.length_);
    if (0 == r) {
      if (length_ < str.length_)
        r = -1;
      else if (length_ > str.length_)
        r = 1;
    }
    return r;
  }

 private:
  const char* ptr_;
  size_t length_;
};

As the comment mentioned above, the StringPiece is designed to 1)save some unnecessary data copying and 2) receive two different type parameter in an object. I write some code to learn how to use StringPiece, I got some error. My code is as follow:

#include "StringPiece.h"
#include <iostream>
using namespace std;

void foo1(string&& str){
    cout << str << endl;
}

void foo1(const StringPiece& str){
    cout << str.as_string() << endl;
}

int main(void){
    foo1("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    return 0;
}

The error I got as follow: enter image description here

In my opinion, StringPiece is a little bit like a boost::string_ref. It can give you a glimpse of the string it doesn't own. So I think it is necessary to provide an overload version of foo1 which receive a rvalue string parameter. Is any to work around this problem here? I means that only in the case when I use unnamed string object as parameter, the foo1(string&&) will be called. And in other case, including use const char* as parameter, the foo1(const StringPiece&) will be called.

Aucun commentaire:

Enregistrer un commentaire