標籤:

muduo::StringPiece?

在學習muduo的源碼,這個類的源碼是這樣的,

class StringPiece
{
private:
const char* ptr_;
int length_;
public:
StringPiece() : ptr_(NULL), length_(0) { }
StringPiece(const char* str): ptr_(str), length_(static_cast&(strlen(ptr_))) { }
StringPiece(const unsigned char* str): ptr_(reinterpret_cast&(str)),length_(static_cast&(strlen(ptr_))) { }
StringPiece(const std::string str) : ptr_(str.data()), length_(static_cast&(str.size())) { }
StringPiece(const char* offset, int len) : ptr_(offset), length_(len) { }
const char* data() const { return ptr_; }
int 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_ = NULL; length_ = 0; }
void set(const char* buffer, int len) { ptr_ = buffer; length_ = len; }
void set(const char* str) { ptr_ = str; length_ = static_cast&(strlen(str)); }
void set(const void* buffer, int len) { ptr_ = reinterpret_cast&(buffer); length_ = len; }
char operator[](int i) const { return ptr_[i]; }
void remove_prefix(int n) { ptr_ += n; length_ -= n; }
void remove_suffix(int n) { length_ -= n; }
bool operator==(const StringPiece x) const { return ((length_ == x.length_) (memcmp(ptr_, x.ptr_, length_) == 0)); }
bool operator!=(const StringPiece x) const { return !(*this == x); }
std::string as_string() const { return std::string(data(), size());}
void CopyToStdString(std::string* target) const { target-&>assign(ptr_, length_); }
bool starts_with(const StringPiece x) const { return ((length_ &>= x.length_) (memcmp(ptr_, x.ptr_, x.length_) == 0)); }
int compare(const StringPiece x) const
{
int r = memcmp(ptr_, x.ptr_, length_ &< x.length_ ? length_ : x.length_); if (r == 0) { if (length_ &< x.length_) r = -1; else if (length_ &> x.length_) r = +1;
}
return r;
}

這兩個函數理解的不是很清楚,為什麼不驗證ptr這個指針指向的字元串長度呢?

remove_suffix為什麼僅僅只是改變了長度,沒有將末尾填寫成""呢?

void remove_prefix(int n) { ptr_ += n; length_ -= n; }

void remove_suffix(int n) { length_ -= n; }

是不是有更深層次的考慮?


就是string view


這個類實際上只是對字元串的一個proxy類而已(即設計模式中的代理模式),通常叫做string view.它提供了一個窗口,外部僅可以觀察到這個窗口中字元串的內容,在調整窗口大小時不需要修改原字元串,僅移動開始指針和調整長度即可。另外這個類自身並不存儲這個字元串,所以它的有效生存期取決於源字元串指針的生存期。

好的,現在看題主的問題:

1. 這兩個函數理解的不是很清楚,為什麼不驗證ptr這個指針指向的字元串長度呢?

長度是由length來控制的。

2. remove_suffix為什麼僅僅只是改變了長度,沒有將末尾填寫成""呢?

現在假設我們有這樣一個初始字元串"abcde",它的窗口為[0, length),其中length = 5。

那麼如果我們想去掉"ab"這兩個前置字元怎麼辦呢?注意我們是一個代理類,不需要去操作源串,只需要修改ptr_指針,讓它前進兩格就可以了。

但是前進之後,長度變短了,這時需要把length_減去n;這時的窗口為[2, length)

那如果是想去掉"de"呢?只需要把length_減去n就好了。這時的窗口為[0, length - 2)

void remove_prefix(int n) { ptr_ += n; length_ -= n; }

void remove_suffix(int n) { length_ -= n; }

所以題主應該看出來了,這樣的字元串不可能是以""作為結束符的。它有獨立的length_來保證長度,同時,operator ==等函數的行為也保證了它只以length_作為終止的判斷。

回到原來的代碼上。

這段代碼可能有如下問題:

1. remove_prefix和remove_suffix都有可能把length_減成負值。這時候最好assert一下以防萬一。因為memcmp()的第三個參數是unsigned int型的,負值可能會變成一個很大的正值導致出錯。同時ptr也有可能會移出合法的內存區。

2. 另外個人覺得length最好用size_t類型保存。

3. CopyToStdString函數中先assert(target != nullptr);可能好些。我自己的習慣是CopyToStdString(std::string target); 直接用引用。不過據說某公司(從群里聽聞的)有傳修改的值用指針,傳const值用const引用的規定。-_-!


應該是類似於 Boost.Utility 中的 string_ref 的東東。


首先搞清為什麼要有這個類

C++裡面有string和char*,如果你用const string s 做函數形參,可以同時兼容兩種字元串。但當你傳入一個很長的char * 時,會生成一個較大的string對象,開銷比較大。

如果你的目的僅僅是讀取字元串的值,用這個StringPiece的話,僅僅是4+一個指針的內存開銷,而且也保證了兼容性。

所以這個類的目的是傳入字元串的字面值,它內部的ptr_ 這塊內存不歸他所有。所以不能做任何改動。

另外這裡的ptr_也聲明為const,這也作者的本意就是只讀。


// Taken from PCRE pcre_stringpiece.h
//
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Author: Sanjay Ghemawat
//
// A string like object that points into another piece of memory.
// Useful for providing an interface that allows clients to easily
// pass in either a "const char*" or a "string".
//


不懂。感覺這個類是個私用的類。


意思就是說這不是一個0結尾的字元串吧。有很多語言也是這樣的,譬如Pascal、Delphi、C#,還有COM的ABI什麼的。


const char* ptr_; 沒法修改


應該是出於性能考慮,將驗證工作交由調用者處理,至於為什麼不設置成0,看這個類的構造函數都是const類型,應該是該類只用於提取,而不用於修改


推薦閱讀:

嵌入式這行業是不是不行了?
使用sprintf時溢出怎麼會影響到變數的值?
小弟做c++伺服器差不多一年了,用ace框架的,還沒什麼信心,還很菜,請教各位大神如何提升進階啊?
計算機專業C++應該怎麼教?
計算機中缺失MSVCP120D.dll和MSVCR120D.dll怎麼解決?

TAG:C | muduo |