2016-07-13 63 views
3

我一直想知道std::stringsubstr(pos, len)方法現在有一段時間的設計背後的基本原理。它對我仍然沒有意義,所以我決定詢問專家。如果pos參數超過字符串長度加1,該函數會拋出std::out_of_range異常。這可能有時不方便(甚至令人討厭),但我真正關心的是一致性和最少驚喜的原則。事實證明子字符串的「結束」位置pos+len被允許超過字符串長度加1。在開始時禁止這種做法,但並不是爲了最終的結果,這讓我感到不一致。允許它到底要我在解釋爲什麼std :: string :: substr會拋出異常而不是返回空字符串?

回報暗示位置的所有字符pos <= i < pos+len

但是,那麼我希望函數返回一個空字符串超過字符串長度的pos值,而不是拋出異常。作爲一個方面說明,根據這種解釋,如果允許負值pos(假設它具有簽名類型),則更爲明智。

這給我留下了以下問題:

  • 這是否設計出現合乎邏輯的嗎?明智?你有解決不一致問題的令人滿意的方法嗎? 我能想出的唯一可能的解釋是與以空字符結尾的字符串兼容。有了空終止,如果指定的長度超過了結尾,則無關緊要,而超出空字符的開始是內存錯誤。然而,std::string而不是以空終止,而是跟蹤字符串的長度。如果這是真正的原因,那麼我個人會說這是一個非常糟糕的。
  • 在性能方面有優勢嗎?我真的會感到驚訝。
  • 我是否忽略了可用性方面的優勢?也許一個標準的習慣用法或用例與其他函數一起使用,比如find?在這裏我的印象是返回一個空字符串有可能簡化一些代碼。
  • 以後有什麼方法可以改變substr的行爲嗎?我猜不是的,因爲默默地破壞現有的代碼必須比生活在這種扭曲中更糟糕......?
+1

它可以很容易地說「從pos'到末尾的子串」,這不是一種不常見的操作。將第二個參數想象爲返回子字符串中字符數的上限。 –

+0

這個問題可能太基於觀點了。您將呈現一個有趣的字符串視圖,就像無限大的虛擬字符緩衝區,您可以從中選擇一個切片,即使在物理範圍之外。不過,我認爲,更細微的錯誤不會被發現。通過拋出一個範圍異常,你至少可以捕捉一些計算得很差的位置值。也許這是原因? – Galik

+1

我一直都這樣說,在合同違約(這裏的前提條件)上拋出異常是糟糕的設計,即使異常是您合同的一部分。調用者會做什麼,捕獲異常並用'pos/= 2'循環調用函數,直到它停止投擲爲止?更好地斷言 - 失敗並提供有用的信息(例如:「消毒您的輸入!」)。但是,STL是很多年前寫的,也許當時人們並不知道更好。現在,我們必須忍受這種行爲。 – KABoissonneault

回答

2

這個問題真的太基於觀點,但我會盡量逐點回答。

  • 此設計對您來說是否合乎邏輯?明智?對我來說這似乎合乎邏輯。也許這樣的意見來自strncmp風格的函數,但有了這樣的設計,你可以傳遞你的緩衝區長度爲len參數,它會正常工作。但是,如果您嘗試訪問位於字符串邊界之外的子字符串,那麼您可能會錯過一些簡單的理智檢查。 std::string的內部執行並不重要。
  • 在性能方面是否有優勢?我認爲這不是原因。
  • 我是否忽略了可用性方面的優勢?也許,看看第1點。
  • 有什麼方法可以改變substr在未來的行爲嗎?投標例外pos超過size()是在標準中定義的,所以最有可能不是。

我的觀點是:這個例外(雖然我更喜歡從不使用這些)允許您注意缺少一些基本理智檢查的代碼,例如訪問邊界外的緩衝區。在類似at()的功能和其他許多功能中使用相同的設計。

+0

感謝您的回答。我覺得在超越結尾的開始之前是否超出結束範圍是有爭議的,但正如你所說,這只是因爲習慣了strncmp和朋友(包括'std :: string :: substr')。我最喜歡的例子'size_t pos = s.find(''); string cmd = s.substr(0,pos);字符串args = s.substr(pos + 1)'是一個合理的用例,我希望空字符串超出例外,而不會錯過「基本」的完整性檢查(沒有arg是好的)。使用'len'的緩衝區大小是很方便的,這裏同樣適用於'pos'。 – tglas

+0

那麼,你總是可以在'std :: string'周圍寫一些類,並使它像你想要的那樣工作。 – Ternvein

+0

其實這就是我所做的(一個簡單的免費功能),但它惹惱了我:) – tglas

相關問題