c 中明明有vector了為什麼還要有stack?

時間 2021-05-06 19:16:19

1樓:飛翔的荷蘭豬

作為乙個類的設計者,不僅要考慮類的使用者所需要的的功能,也要考慮如何限制類使用者的不當操作。

同樣當需要乙個stack的時候,很有可能下標訪問,中間插入等操作,會影響物件本身功能的時候。要限制這種操作,一是注釋告訴物件使用者,禁止使用下標訪問等操作,當更好的辦法是,從根本上就不提供這樣的介面,讓編譯器來強制對物件的操作。

2樓:

stack下可以使用vector做容器,是zero-overhead abstraction。 遮蔽了一些vector不必要的介面,充分維護了stack這一先入後出容器的概念。 容器配接器(container adapter)和容器分離是STL做的比較好的一點,這給予了我們根據不同需要切換內部容器的自由。

談點題目外的:

談到容器配接器和容器,就不得不提到map。現在主流STL中的map的實現其實更像乙個容器配接器,而不是容器。容器是內部的紅黑樹。

set,multiset, map, multimap都是對rb_tree這一容器的不同配接器。可惜標準庫沒有提供切換map和set底層容器的方法。

3樓:

分工不同,為了型別安全著想。

stack(類似還有queue、priority_queue)是個容器介面卡,專門就是用來表示那種先入後出的結構,不允許使用者故意或者意外地有其他操作破壞棧的先入後出、只能訪問棧頂的特性,以免發生意外。聯想到了private、protected的意義。順帶的好處,確實,介面的名字變短了。

vector可以作為stack的容器,但看stack的原始碼可以發現只要有那幾個介面的容器應該都能做它的容器吧。

4樓:被子飛了

開發 Rust 的人似乎也是這麼想的,所以標準庫里有包含 push 和 pop 方法的 Vec 而沒有單獨的 Stack 型別,結果……好像沒啥結果。

5樓:果凍蝦仁

首先手頭常備乙份C++ API文件,比如:http://www.

。關於STL容器的API你都可以查。比如:

關於stack,允許我引用一下:

LIFO stack

Stacks are a type of container adaptor, specifically designed to operate in a LIFO context (last-in first-out), where elements are inserted and extracted only from one end of the container.

stacks are implemented as containers adaptors, which are classes that use an encapsulated object of a specific container class as its underlying container, providing a specific set of member functions to access its elements. Elements are pushed/popped from the"back"of the specific container, which is known as the top of the stack.

The underlying container may be any of the standard container class templates or some other specifically designed container class. The container shall support the following operations:

empty

size

back

push_back

pop_back

The standard container classes vector,deque and list fulfill these requirements. By default, if no container class is specified for a particular stack class instantiation, the standard container deque is used.

開宗明義第一句:

Stacks are a type of container adaptor

stack是乙個容器介面卡型別。這裡的介面卡adaptor就是取自設計模式中介面卡模式。那麼什麼是介面卡?電源介面卡,大家都見過吧!

不管是各式各樣的Windows還是Macbook。通電的電源線上都有一大坨。對於插進插線板通電這回事,兩個鐵片支腳就行了,幹嘛要做這麼醜的一坨。

答案大家也都知道了,那就是插線板裡的是220V的交流電,而我們的筆記本只需要十幾V的直流電。

介面卡就完成這中間的轉換,給筆記本供電的是電源介面卡麼,不是。

介面卡模式同樣如此,提供實際資料結構儲存和操作的另有其人,它只是一層封裝,將其他容器的介面,模塑成了符合離散數學中棧定義的操作模式。

去看stack的宣告:

template

class

Container

=deque

>class

stack

;模板引數二可以指定容器型別,預設的時候是deque。你當然也可以傳入vector、list。

對於乙個數學意義上的棧而言,你應該只關心入棧的一端,而不應該去關心出棧那端,更不應該去關心,棧中任意位置的其他元素。如果你的程式需要關心這些,對不起。請不要用棧。

再做個假設,假如你要設計某個庫或框架給公司的其他團隊使用,裡面涉及到乙個棧的資料結構。用vector當然可以實現,不停的push_back和pop_back唄。但是你如果提供出去,你怎麼能保證使用者可以如你所願,如果他們任意修改了任意位置的元素,是否會為線上事故埋下隱患?

STL的設計哲學,除了方便之外,就是苦口婆心地讓大家避免濫用容器。避免程式設計師因為有了STL,不用手寫資料結構了,就濫用容器。就和寫業務邏輯的程式設計師喜歡濫用RPC一樣(就像呼叫乙個普通函式那樣呼叫了乙個遠端方法,但是它真的是要消耗時間的)

要做到避免濫用,不提供相應的操作介面就可以了。比如這個stack,就不提供tail()、不提供,是實現不了嗎?肯定不是。

類似的地方還有很多,比如迭代器為什麼要分那麼多種,list為什麼不能提供,它的迭代器為什麼不能+n,只能+1。+n能實現麼,肯定也可以,內部多遍歷幾遍唄。但是就不提供你這個便利,怕的就是濫用;為什麼vector都沒有乙個自帶的sort成員函式,而list會提供乙個。

這個當然是怕你把std::sort 用list身上,但STL作者又不希望大家手寫乙個鍊錶排序,所以提供給你好了。藉此你也可以了解到鍊錶的排序和陣列是不同的。

總而言之,STL在提供方便的同時,也帶著限制。看似帶著鐐銬跳舞,但是用多了,你會發現自己身輕如燕。那些被封禁的操作,是對程式設計師的保護,也是教化!

6樓:一鳴道長

拓展一下:如果型別 A 在語義上是型別 B 的子集,那麼只需要 B 的情況下使用 A 實際上允許了預期之外的行為,如你提到的下標操作,這樣型別約束就變弱了

另外,stack 其實是乙個帶有兩個型別引數的 type constructor

template

class

Container

=std

::deque

>class

stack

;接受乙個元素型別和乙個具體的容器型別(預設是 deque),生成具體的 stack 型別

你可能在想為什麼 stack 不設計成 Higher-kinderd type ,第二個引數是另乙個 type constructor,這樣你就只需要寫 std::stack,而不是 std::stack>,這是因為 std::

vector 不止有乙個型別引數,而且即使繞過這個問題,也不見得就簡單,見: https://

C 中為什麼有delete 這種寫法?

因為物件導向的,所以很麻煩.如果delete既能釋放乙個元素,又能釋放乙個陣列,會造成混淆,還會在申請釋放時做額外的判斷,浪費額外的記憶體.那樣的話不如乾脆不提供new 了.自己建立陣列儲存.CT t 10 for int i 0 i 10 i 陳碩 新的標準和編譯器擴充套件為什麼不能實現這個簡單的...

C 中為什麼要有allocator類?

Wu Jarvis 我是這麼理解的 其實你只要分清vector中resize,reserve的關係就能明白了,resize時,當元素數量 capacity時不但會分配空間,而且會初始化元素 reserve只會做分配空間的事情,不會做初始化,這樣就把分配空間和初始化的事情分開來了,如果不分開的話,那麼...

為什麼C 中沒有階乘函式?

呂不鬧 如果只是問為什麼,那麼答案應該是 委員會那些老學究不允許太多無關緊要的功能進入標準。可能他們覺得 CPPer 都能自己寫出來吧。 簡易版 include include include include include using namespace std intmain O 1 版 inc...