2011-02-03 35 views
19

Tại sao std :: stack :: pop() không ném ngoại lệ nếu ngăn xếp trống và không có gì để bật?Câu hỏi ngăn xếp C++ STL: Tại sao pop() không ném ngoại lệ nếu ngăn xếp trống?

(Tôi đang thiết kế một Stack chuyên cho mã của riêng tôi và muốn biết cân bằng với phương pháp này (mà đòi hỏi phải có một tự kiểm tra xem stack rỗng) vs ném một ngoại lệ.

My đoán ở đây sẽ là mặc dù C++ hỗ trợ xử lý ngoại lệ, nó đi kèm với một chi phí thời gian chạy nhỏ, và do đó, để thực hiện tối đa, quyết định đã được thực hiện không để ném một ngoại lệ trong std :: stack :: pop).

+5

Bạn đã đoán gần đúng. Nó không phải là chi phí của trường hợp ngoại lệ đó là vấn đề. Nó sẽ kiểm tra nếu ngăn xếp trống mỗi lần. Nếu bạn sử dụng std :: stack, bạn sẽ được biết (hoặc tự kiểm tra) khi nó trống. –

+1

Tôi không chắc mình hiểu cách kiểm tra ngăn xếp trống trước khi mỗi cửa sổ bật lên không hiệu quả. Nó sẽ là một so sánh hằng số rất nhỏ để thực hiện, đúng không? – PlagueHammer

+0

@Nocturne: Nó sẽ nhỏ, nhưng nó vẫn sẽ là một cái gì đó. Cái gì> Không có gì. Điều đó nói rằng, std :: stack là một adapter container, do đó, nó chỉ làm bất cứ điều gì container tiềm ẩn trong trường hợp này. –

Trả lời

8

Bạn đã chính xác. Tiêu chuẩn C++ luôn thích hiệu suất đến mức an toàn. Nhưng có thể có các triển khai STL bao gồm kiểm tra phạm vi gỡ lỗi.

+0

Và đó là lý do (hiệu quả) mà STL yêu cầu bạn gọi value_type & top() theo sau là void pop(), thay vì có một pop() trả về theo giá trị. –

+10

@Nathan: Những người được tách ra để đảm bảo an toàn ngoại lệ. Nếu ctor sao chép ném trong khi trở về từ cửa sổ bật lên trả về giá trị, bạn vừa mới rò rỉ mục nằm trên chồng (tức là mục bị mất và bạn cũng không thể khôi phục mục đó vào ngăn xếp). Xem: http://www.gotw.ca/gotw/008.htm –

+0

@Jerry đã phát hiện ra! Nó không liên quan gì đến sự hoàn hảo. Trong thực tế, buộc các nhà phát triển gọi top trước khi pop tồi tệ hơn về hiệu suất ... –

1

ngoại lệ là tùy chọn và STL muốn khả dụng ở mọi nơi. nghĩ rằng các hệ thống nhúng: rất nhiều mã C++, không hỗ trợ ngoại lệ từ thời gian chạy.

+2

Vì vậy, trong một hệ thống nhúng, vector :: at() và mới không ném ngoại lệ ở tất cả? – PlagueHammer

+4

"nhiều mã C++, không hỗ trợ ngoại lệ từ runtimes" Có vẻ mâu thuẫn với tôi. C++ rất rõ ràng có ngoại lệ, nếu nền tảng của bạn không hỗ trợ nó, bạn không sử dụng C++, bạn đang sử dụng một dẫn xuất thực hiện cụ thể của C++. – GManNickG

2

Hiệu suất sang một bên, tôi không nghĩ rằng popping từ một ngăn xếp trống là một kịch bản đặc biệt - do đó tôi sẽ không ném có một trong hai.

+0

Tôi cho rằng đó là một kịch bản đặc biệt.Cho rằng bạn sẽ được kiểm tra cho các ngăn xếp trống anyway (hầu hết các thuật toán có kiểm tra này được xây dựng trong), cố gắng để bật một chồng trống sẽ là một ngoại lệ. –

+2

+1 Cảm ơn bạn đã là tiếng nói của lý do tại đây. Ngoại lệ không nên được ném để đáp ứng với điều kiện tiên quyết không thành công mà người gọi có thể (dễ dàng) kiểm tra. –

5

Như hầu như tất cả các tính năng trong C++, chúng được thiết kế xung quanh khái niệm mà bạn không trả tiền cho những gì bạn không sử dụng. Không phải tất cả các môi trường đều hỗ trợ ngoại lệ, theo truyền thống và đáng chú ý nhất là phát triển trò chơi.

Vì vậy, buộc sử dụng ngoại lệ nếu bạn sử dụng std :: stack sẽ không thực hiện được một trong các nguyên tắc thiết kế. Bạn muốn có thể sử dụng ngăn xếp ngay cả khi ngoại lệ bị tắt.

3

Tôi nghĩ đáng lưu ý rằng pop()được phép để ném nếu ngăn xếp trống - không cần thiết. Trong ngăn xếp của bạn, bạn có thể assert rằng ngăn xếp không trống, và điều đó sẽ hoàn toàn tốt đẹp (pop trên một ngăn xếp trống dường như cung cấp cho UB, vì vậy bạn có thể làm khá nhiều bất cứ điều gì bạn muốn, thực sự).

+0

Ở đâu tài liệu được cho rằng pop() được phép ném? Spec có xác định điều này không? – PlagueHammer

+3

@Nocturne: §17.4.4.8/3: "Bất kỳ chức năng nào khác được xác định trong Thư viện chuẩn C++ không có đặc tả ngoại lệ có thể ném ngoại lệ được xác định thực hiện trừ khi được chỉ định khác." Không có đặc tả ngoại lệ nào được đưa ra cho 'std :: stack :: pop()'. Nó chỉ gọi 'pop_back', mà dường như không có một đặc tả ngoại lệ. –

+0

Với tôi, tôi nghĩ điểm quan trọng hơn là 'push_back()' được định nghĩa để thực hiện 'a.erase. (- a.end())' là UB nếu 'a.begin() == a. end() 'và đây là những gì cho phép" bất cứ điều gì xảy ra ". 'erase' thường được đảm bảo để không ném gì cho' list' và không có gì nếu nhà xây dựng bản sao hoặc toán tử gán của kiểu được chứa không ném cho 'vector' và' deque'; đây là những thùng chứa mà bạn thường xây dựng một 'chồng' với. –

11

Tôi cho rằng lý do pop() không phải ném một ngoại lệ có không có gì để làm với hiệu quả hoặc hiệu suất, nhưng với - ngoại lệ.

Như người ta lập luận elsewhere:

  1. SGI giải thích: http://www.sgi.com/tech/stl/stack.html Người ta có thể tự hỏi tại sao pop() trả về bãi bỏ, thay vì value_type. Tức là, tại sao phải sử dụng đầu() và pop() để kiểm tra và loại bỏ phần tử trên cùng, thay vì kết hợp hai thành phần trong một hàm thành viên đơn lẻ ? Trong thực tế, có là một lý do chính đáng cho thiết kế này. Nếu pop() trả về phần tử trên cùng, nó sẽ phải trả về giá trị thay vì so với tham chiếu: trả về theo tham chiếu sẽ tạo ra một con trỏ lơ lửng. Tuy nhiên, Trả lại theo giá trị, là không hiệu quả: nó liên quan đến ít nhất một cuộc gọi hàm sao chép dự phòng .Kể từ , không thể bật() trả lại giá trị theo cách sao cho cả hiệu quả và chính xác, nhiều hơn hợp lý để không trả lại giá trị tất cả và yêu cầu khách hàng sử dụng đầu () để kiểm tra giá trị ở đầu trang của ngăn xếp.

  2. std :: stack < T> là mẫu. Nếu pop() trả về phần tử trên cùng, nó sẽ phải trả về giá trị thay vì so với tham chiếu theo giải thích ở trên giải thích. Điều đó có nghĩa là, ở phía người gọi , nó phải được sao chép theo một loại đối tượng T khác. Điều đó liên quan đến một nhà xây dựng bản sao hoặc sao chép chuyển nhượng cuộc gọi của nhà điều hành. Điều gì sẽ xảy ra nếu loại T này là đủ tinh vi và nó ném một ngoại lệ trong khi sao chép hoặc gán bản sao? Trong trường hợp đó, giá trị , nghĩa là hàng chồng (trả lại theo giá trị) chỉ đơn giản là bị mất và có không có cách nào khác để truy xuất nó từ ngăn xếp khi hoạt động pop của ngăn xếp là hoàn tất thành công!

Khi chúng tôi kết luận rằng nhạc pop nên không trở lại các yếu tố nó bật và do đó giao diện của nó là cố định như void pop(), nó - là quan điểm của tôi này - không có ý nghĩa gì nữa để quy định những gì xảy ra khi pop() được gọi trên một ngăn xếp trống.

Lưu ý rằng tiêu chuẩn yêu cầu !empty() làm điều kiện tiên quyết để gọi pop().

UncleBens (trong nhận xét) chắc chắn có điểm không kiểm tra điều kiện tiên quyết trong thời gian chạy (không bao giờ được quy định bởi C++ std AFAIK) có mùi hiệu suất nhất định. Tuy nhiên, để trích dẫn một phần của câu hỏi ban đầu: (tôi nhấn mạnh)

(Tôi đang thiết kế một Stack chuyên cho mã của riêng tôi và muốn biết cân bằng với phương pháp này (mà đòi hỏi một tự kiểm tra xem ngăn xếp rỗng) vs ném một ngoại lệ .

tôi sẽ lập luận, mà thực tế là pop() không trả lại bất cứ điều gì làm cho câu hỏi tranh luận. Nó (IMHO) chỉ đơn giản doesn' t có ý nghĩa để buộc pop() để xác thực nếu ngăn xếp trống, khi chúng tôi thực sự không nhận được bất kỳ thứ gì từ nó (tức là nếu ngăn xếp sẽ trống pop() có thể chỉ đơn giản là một noop, đó là (thừa nhận) không được quy định bởi Std hoặc).

Tôi nghĩ người ta có thể hỏi tại sao top() không ném ngoại lệ hoặc người ta có thể hỏi tại sao pop() không trả về phần tử trên cùng. Nếu pop không trả lại bất cứ điều gì, ném một ngoại lệ không có ý nghĩa (trong thế giới C++) - Tuyên bố rằng nó không ném một ngoại lệ "vì các chi phí thời gian chạy của trường hợp ngoại lệ" như câu trả lời khác dường như ngụ ý là - IMHO - thiếu điểm.

+0

Cảm ơn, đó là thông tin. Bạn có thể cung cấp một liên kết mà tôi có thể truy cập vào tiêu chuẩn C++ không? – PlagueHammer

+2

Tôi không thấy, tuy nhiên, cách chọn không thực thi các điều kiện tiên quyết trong thời gian chạy có liên quan đến bất kỳ điều gì khác ngoài hiệu suất ... – UncleBens

+0

@UncleBens - Tôi nghĩ đối số ngoại lệ là hấp dẫn nhất. Không thể cho ':: std :: stack :: pop' để đáp ứng sự bảo đảm ngoại lệ mạnh mẽ nếu nó trả về phần tử trên cùng. – Omnifarious

Các vấn đề liên quan