[問題] std::string 的空間是否連續?

看板C_and_CPP作者 (我要加入劍道社!)時間14年前 (2010/04/13 10:08), 編輯推噓9(9014)
留言23則, 10人參與, 最新討論串1/1
嗯,雖然用了「問題」當標題,但這篇其實是一整個自問自答,而且我相信很多 人早就知道答案了。 想像一下,如果我們要把某個文字檔的內容直接讀進某個 C++ string 中,大概 會用如下的方法: string ReadFile(const char* filename) { ifstream fin(filename, ios::binary); fin.seekg(0, ios::end); size_t len = fin.tellg(); // get the file size fin.seekg(0, ios::beg); vector<char> buf(len); // allocate a buffer for fin.read() fin.read(&buf[0], len); return string(&buf[0], len); } 因為 vector 保證它的儲存空間是連續的,所以我們可以用 vector 來當作 fin.read 的 buffer。不過這樣勢必要多一次額外的資料複製。我們能不能 改成這樣呢: string ReadFile(const char* filename) { ifstream fin(filename, ios::binary); fin.seekg(0, ios::end); size_t len = fin.tellg(); // get the file size fin.seekg(0, ios::beg); string buf(len, 0); // allocate a buffer for fin.read() fin.read(&buf[0], len); return buf; } 直接拿 string 的內部空間來接收 fin.read 的資料。而這樣做是否可行,取決 於 string 內部是否使用連續的空間來儲存字串。 根據一陣子的 google 之後,結論是這樣的: 1. C++ 標準是沒有很明確地說 std::string 的空間必須連續,但你很難實作出 一個符合標準卻又不使用連續空間的 std::string。事實上目前所有的實作 都使用連續空間。 2. 未來的 C++0x 標準會明確要求 std::string 的儲存空間必須連續。 3. 事實上在舊的 C++98 標準中也沒有嚴格規定 std::vector 使用連續的儲存 空間,不過發生的問題就如同 std::string 一樣:很難實作出空間不連續 卻又符合標準的 std::vector、既存的實作品都使用連續空間、不使用連續 空間會讓 client code 用起來很不方便等等。最後到了 C++03 就明確要求 std::vector 須要使用連續儲存空間了。 參考連結: * Is std::string’s storage contiguous? http://ppt.cc/n0RP * Cringe not: Vectors are guaranteed to be contiguous http://ppt.cc/,0Py * C++ Standard Library Defect Report: 530. Must elements of a string be contiguous? http://ppt.cc/UR_6 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.112.29.108

04/13 10:48, , 1F
先推, 晚點再回來看XD
04/13 10:48, 1F

04/13 12:16, , 2F
不是有 c_str 可用嗎?
04/13 12:16, 2F

04/13 12:24, , 3F
c_str 只能讀不能寫唷 *.<
04/13 12:24, 3F

04/13 12:55, , 4F
不過會有什麼影響啊?連不連續的問題?@@?
04/13 12:55, 4F

04/13 13:06, , 5F
c_str不能寫嗎?我用過怎是可以寫不能讀
04/13 13:06, 5F

04/13 13:07, , 6F
大概是你用到外星科技版的實作品了
04/13 13:07, 6F

04/13 13:08, , 7F
c_str() 回傳型態是"const char*"
04/13 13:08, 7F

04/13 14:53, , 8F
嗯, 如果不用連續空間來實作, 各種效益上都比較差
04/13 14:53, 8F

04/13 14:55, , 9F
喔喔..可以理解..Thx~
04/13 14:55, 9F

04/13 16:06, , 10F
為什麼不用 ostringstream 物件, 然後把 fin的資料 '<<'
04/13 16:06, 10F

04/13 16:07, , 11F
進去,最後直接回傳 ostrm.str() 就好了?這樣比較簡潔吧?
04/13 16:07, 11F

04/13 16:15, , 12F
遇到這問題通常都是為了包裝 C-API
04/13 16:15, 12F

04/13 16:23, , 13F
舊式的 C API 在回傳 string 時,往往會要求使用者傳入
04/13 16:23, 13F

04/13 16:24, , 14F
一塊 char* 的 buffer 以及這塊 buffer 的大小,然後
04/13 16:24, 14F

04/13 16:24, , 15F
該函式再把欲回傳的 string 填入這塊 buffer 中。
04/13 16:24, 15F

04/13 16:26, , 16F
本來想拿一段 OpenCL 的 code 當 sample,不過怕模糊
04/13 16:26, 16F

04/13 16:27, , 17F
焦點,就改成以讀檔當作 sample 了。
04/13 16:27, 17F

04/13 18:52, , 18F
sgi rope 不知道有沒有符合 std::string 的介面..
04/13 18:52, 18F

04/13 19:49, , 19F
std::string 規定 operator[](i) 要回傳 data()[i]
04/13 19:49, 19F

04/13 19:50, , 20F
而且 operator[](i) 要能夠回傳 non-const reference
04/13 19:50, 20F

04/13 19:50, , 21F
所以看來 rope 是不符合 std::string 的
04/13 19:50, 21F

04/14 00:18, , 22F
這樣做之前有需要先resize(len)嗎? size()會不會有問題?
04/14 00:18, 22F

04/14 09:05, , 23F
string(len, 0) 會建構一份長度為 len,內容為0的字串
04/14 09:05, 23F
文章代碼(AID): #1Bmz8bKt (C_and_CPP)