Sử dụng hiệu quả các vectơ STL. Scott Meyers - Sử dụng STL hiệu quả


Nhiều cuốn sách mô tả khả năng của STL, nhưng chỉ có cuốn này nói về cách làm việc với thư viện này. Mỗi mẹo trong số 50 mẹo của cuốn sách đều được hỗ trợ bằng các phân tích và ví dụ thuyết phục, vì vậy người đọc sẽ không chỉ học được cách giải quyết một vấn đề cụ thể mà còn biết khi nào nên chọn một giải pháp cụ thể - và tại sao.

“...Không có dải ruy băng nào trên đó cả! Không có lối tắt! Không có hộp và không có túi!” Tiến sĩ Suess, Grinch đã đánh cắp Giáng sinh như thế nào

Lời nói đầu

“...Không có dải ruy băng nào trên đó cả! Không có lối tắt! Không có hộp và không có túi!”

Tiến sĩ Suess, Grinch đã đánh cắp Giáng sinh như thế nào

Lần đầu tiên tôi viết về STL (Thư viện mẫu tiêu chuẩn) vào năm 1995. Cuốn sách “C++ hiệu quả hơn” của tôi đã hoàn thành một tổng quan ngắn gọn thư viện. Nhưng điều này vẫn chưa đủ, và ngay sau đó tôi bắt đầu nhận được tin nhắn hỏi khi nào cuốn sách “STL hiệu quả” sẽ được viết.

Tôi đã phản đối ý tưởng này trong nhiều năm. Lúc đầu, tôi không có đủ kinh nghiệm về lập trình STL và không cho rằng có thể đưa ra lời khuyên. Nhưng thời gian trôi qua, vấn đề này đã được thay thế bằng vấn đề khác. Không còn nghi ngờ gì nữa, sự xuất hiện của thư viện đồng nghĩa với một bước đột phá trong lĩnh vực kiến ​​trúc có khả năng mở rộng hiệu quả, nhưng trong lĩnh vực sử dụng STL, những vấn đề thuần túy thực tế đã nảy sinh mà không thể nhắm mắt làm ngơ. Sự thích ứng của bất kỳ chương trình STL, ngoại trừ những vấn đề đơn giản nhất, có liên quan đến nhiều vấn đề, điều này được giải thích không chỉ bởi sự khác biệt trong cách triển khai mà còn bởi cấp độ khác nhau Hỗ trợ mẫu trình biên dịch. Sách giáo khoa về STL rất hiếm nên việc hiểu “Đạo của lập trình STL” không phải là một việc dễ dàng. Và ngay khi lập trình viên đối mặt với khó khăn này, một khó khăn khác lại nảy sinh - việc tìm kiếm tài liệu tham khảo đủ đầy đủ và chính xác. Ngay cả lỗi nhỏ nhất khi sử dụng STL cũng đi kèm với hàng loạt thông báo chẩn đoán trình biên dịch, độ dài của chúng lên tới vài nghìn ký tự và trong hầu hết các trường hợp, chúng là về các lớp, hàm và mẫu không được đề cập trong chương trình. Với tất cả sự tôn trọng dành cho STL và các nhà phát triển thư viện này, tôi đã do dự khi giới thiệu nó cho các lập trình viên cấp trung. Tôi không chắc STL có thể được sử dụng hiệu quả hay không.

Sau đó tôi nhận thấy một điều đáng kinh ngạc. Bất chấp tất cả các vấn đề về chuyển và chất lượng tài liệu kém, bất chấp các thông báo của trình biên dịch giống như một mớ ký hiệu lộn xộn vô nghĩa, nhiều khách hàng của tôi vẫn làm việc với STL. Hơn nữa, họ không chỉ thử nghiệm thư viện mà còn sử dụng nó trong các phiên bản thương mại của chương trình của họ! Đó là một sự mặc khải đối với tôi. Tôi biết rằng các chương trình sử dụng STL có kiến ​​trúc tao nhã, nhưng bất kỳ thư viện nào mà lập trình viên sẵn sàng gặp khó khăn khi chuyển, tài liệu kém và thông báo lỗi khó hiểu đều phải có thứ gì đó hơn là kiến ​​trúc tốt. Ngày càng có nhiều lập trình viên chuyên nghiệp tin rằng ngay cả việc triển khai STL không tốt vẫn tốt hơn là không triển khai gì cả.

Hơn nữa, tôi biết rằng tình hình với STL sẽ được cải thiện. Các thư viện và trình biên dịch sẽ dần dần tiến gần hơn đến các yêu cầu của Tiêu chuẩn (đây là cách nó đã xảy ra), tài liệu chất lượng cao sẽ xuất hiện (xem danh sách tài liệu tham khảo ở trang 203) và chẩn đoán trình biên dịch sẽ trở nên dễ hiểu hơn (trong lĩnh vực này, tình huống còn nhiều điều đáng mong đợi, nhưng những khuyến nghị của Hội đồng 49 sẽ giúp bạn giải mã tin nhắn). Vì vậy, tôi quyết định đóng góp cho phong trào STL. Đây là cách cuốn sách này xuất hiện - 50 lời khuyên thiết thực về việc sử dụng STL trong C++.

Lúc đầu tôi định viết một cuốn sách vào nửa cuối năm 1999 và thậm chí còn phác thảo ra cấu trúc thô của nó. Nhưng sau đó kế hoạch thay đổi, tôi tạm dừng công việc viết cuốn sách và phát triển một khóa học giới thiệu về STL, khóa học này được dạy cho một số nhóm lập trình viên. Khoảng một năm sau, tôi quay lại cuốn sách và mở rộng tài liệu rất nhiều dựa trên những kinh nghiệm tôi có được khi giảng dạy. Trong cuốn sách, tôi đã cố gắng đề cập đến các khía cạnh thực tế của việc lập trình trong STL, đặc biệt quan trọng đối với các lập trình viên chuyên nghiệp.

Scott Douglas Meyers Stafford, Oregon tháng 4 năm 2001

Lời nói đầu

“...Không có dải ruy băng nào trên đó cả! Không có lối tắt! Không có hộp và không có túi!”

Tiến sĩ Suess, Grinch đã đánh cắp Giáng sinh như thế nào

Lần đầu tiên tôi viết về STL (Thư viện mẫu tiêu chuẩn) vào năm 1995. Cuốn sách “C++ hiệu quả hơn” của tôi đã kết thúc với phần tổng quan ngắn gọn về thư viện. Nhưng điều này vẫn chưa đủ, và ngay sau đó tôi bắt đầu nhận được tin nhắn hỏi khi nào cuốn sách “STL hiệu quả” sẽ được viết.

Tôi đã phản đối ý tưởng này trong nhiều năm. Lúc đầu, tôi không có đủ kinh nghiệm về lập trình STL và không cho rằng có thể đưa ra lời khuyên. Nhưng thời gian trôi qua, vấn đề này đã được thay thế bằng vấn đề khác. Không còn nghi ngờ gì nữa, sự xuất hiện của thư viện có nghĩa là một bước đột phá trong lĩnh vực kiến ​​trúc có khả năng mở rộng hiệu quả, nhưng trong lĩnh vực này sử dụng STL gặp phải những vấn đề hoàn toàn thực tế mà không thể nhắm mắt làm ngơ. Việc điều chỉnh tất cả ngoại trừ các chương trình STL đơn giản nhất gặp nhiều vấn đề, không chỉ do sự khác biệt trong cách triển khai mà còn do các mức hỗ trợ mẫu trình biên dịch khác nhau. Sách giáo khoa về STL rất hiếm nên việc hiểu “Đạo của lập trình STL” không phải là một việc dễ dàng. Và ngay khi lập trình viên đối mặt với khó khăn này, một khó khăn khác lại nảy sinh - việc tìm kiếm tài liệu tham khảo đủ đầy đủ và chính xác. Ngay cả lỗi nhỏ nhất khi sử dụng STL cũng đi kèm với hàng loạt thông báo chẩn đoán trình biên dịch, độ dài của chúng lên tới vài nghìn ký tự và trong hầu hết các trường hợp, chúng là về các lớp, hàm và mẫu không được đề cập trong chương trình. Với tất cả sự tôn trọng dành cho STL và các nhà phát triển thư viện này, tôi đã do dự khi giới thiệu nó cho các lập trình viên cấp trung. Tôi không chắc chắn về STL Có thể sử dụng hiệu quả.

Sau đó tôi nhận thấy một điều đáng kinh ngạc. Bất chấp tất cả các vấn đề về chuyển và chất lượng tài liệu kém, bất chấp các thông báo của trình biên dịch giống như một mớ ký hiệu lộn xộn vô nghĩa, nhiều khách hàng của tôi vẫn làm việc với STL. Hơn nữa, họ không chỉ thử nghiệm thư viện mà còn sử dụng nó trong các phiên bản thương mại của chương trình của họ! Đối với tôi nó

là một sự mặc khải. Tôi biết rằng các chương trình sử dụng STL có kiến ​​trúc tao nhã, nhưng bất kỳ thư viện nào mà lập trình viên sẵn sàng gặp khó khăn khi chuyển, tài liệu kém và thông báo lỗi khó hiểu đều phải có thứ gì đó hơn là kiến ​​trúc tốt. Ngày càng có nhiều lập trình viên chuyên nghiệp tin rằng ngay cả việc triển khai STL không tốt vẫn tốt hơn là không triển khai gì cả.

Hơn nữa, tôi biết rằng tình hình với STL sẽ được cải thiện. Các thư viện và trình biên dịch sẽ dần dần tiến gần hơn đến các yêu cầu của Tiêu chuẩn (đây là cách nó đã xảy ra), tài liệu chất lượng cao sẽ xuất hiện (xem danh sách tài liệu tham khảo ở trang 203) và chẩn đoán trình biên dịch sẽ trở nên dễ hiểu hơn (trong lĩnh vực này, tình huống còn nhiều điều đáng mong đợi, nhưng những khuyến nghị của Hội đồng 49 sẽ giúp bạn giải mã tin nhắn). Vì vậy, tôi quyết định đóng góp cho phong trào STL. Đây là cách cuốn sách này xuất hiện - 50 lời khuyên thiết thực về cách sử dụng STL trong C++.

Lúc đầu tôi định viết một cuốn sách vào nửa cuối năm 1999 và thậm chí còn phác thảo ra cấu trúc thô của nó. Nhưng sau đó kế hoạch thay đổi, tôi tạm dừng công việc viết cuốn sách và phát triển một khóa học giới thiệu về STL, khóa học này được dạy cho một số nhóm lập trình viên. Khoảng một năm sau, tôi quay lại cuốn sách và mở rộng tài liệu rất nhiều dựa trên những kinh nghiệm tôi có được khi giảng dạy. Trong cuốn sách, tôi đã cố gắng đề cập đến các khía cạnh thực tế của việc lập trình trong STL, đặc biệt quan trọng đối với các lập trình viên chuyên nghiệp.

Scott Douglas Meyers Stafford, Oregon Tháng 4 năm 2001

Từ cuốn sách C++ của Hill Murray

Lời nói đầu Ngôn ngữ định hình cách chúng ta suy nghĩ và quyết định những gì chúng ta có thể nghĩ đến. B.L. Worf C++ là ngôn ngữ phổ quát lập trình, được thiết kế để làm cho việc lập trình trở nên thú vị hơn đối với những lập trình viên nghiêm túc. Ngoại trừ những cái nhỏ

Từ cuốn sách Trung tâm âm nhạc trên máy tính tác giả Leontyev Vitaly Petrovich

Lời nói đầu Khó ai có thể tưởng tượng được một chiếc máy tính hiện đại không có âm thanh. Nhưng lúc đầu thì là như vậy. Máy tính được tạo ra để phục vụ cho công việc tính toán nghiêm túc trong các tổ chức đặc biệt, âm thanh duy nhất của chúng là tiếng ồn của quạt và tiếng vo vo của máy in. VỚI

Từ cuốn sách Microsoft Office tác giả Leontyev Vitaly Petrovich

Lời nói đầu Không còn nghi ngờ gì nữa cái gọi là chương trình văn phòng– Phổ biến nhất và nhiều nhất Các chương trình hữu ích của tất cả những gì có thể sống trong cái bụng sắt của máy tính của bạn. Và nếu bạn đã biết cách khởi động máy tính, cài đặt chương trình, làm việc với

Từ cuốn sách Quy trình vòng đời phần mềm tác giả tác giả không rõ

Từ cuốn sách CÔNG NGHỆ THÔNG TIN. HƯỚNG DẪN QUẢN LÝ TÀI LIỆU PHẦN MỀM tác giả tác giả không rõ

Lời nói đầu 1. ĐƯỢC PHÁT TRIỂN VÀ GIỚI THIỆU bởi Ủy ban Kỹ thuật Tiêu chuẩn hóa TC 22 “Công nghệ thông tin”2. ĐƯỢC PHÊ DUYỆT VÀ CÓ HIỆU LỰC theo Nghị quyết của Tiêu chuẩn Nhà nước Nga ngày 20 tháng 12 năm 1993 số 260. Tiêu chuẩn này được biên soạn trên cơ sở sử dụng văn bản xác thực của tài liệu kỹ thuật.

Từ cuốn sách Nhân tố con người trong lập trình tác giả Konstantin Larry L

Lời nói đầu Phía bên kia phần mềm Cuốn sách này nói về mặt khác của phần mềm - mặt khác xem xét thế giới bên ngoài. Phần này của máy tính là về con người - những người làm công nghệ như bạn và tôi, và những người bình thường giống như bạn và tôi. Những ghi chú sưu tầm ở đây khám phá

Từ cuốn sách 300 chương trình tốt nhất cho tất cả các dịp tác giả Leontyev Vitaly Petrovich

Lời tựa Tất cả những thứ cần thiết nhất trên thế giới này đều có một đặc tính khó chịu nhất: chúng không bao giờ có sẵn vào đúng thời điểm. Khoa học chưa biết đây là hậu quả của “luật bánh sandwich” khét tiếng hay sự đãng trí cơ bản của con người. Kết quả là tất cả

Từ cuốn sách BPwin và Erwin. Công cụ phát triển CASE hệ thông thông tin tác giả

Lời nói đầu Việc tạo ra các hệ thống thông tin hiện đại là một nhiệm vụ khó khăn, giải pháp đòi hỏi phải sử dụng các kỹ thuật và công cụ đặc biệt. Không có gì ngạc nhiên khi ở Gần đâyđã phát triển đáng kể trong số các nhà phân tích và phát triển hệ thống

Từ cuốn sách Mô hình hóa quy trình nghiệp vụ với BPwin 4.0 tác giả Maklakov Sergey Vladimirovich

Lời nói đầu Năm 1998, cuốn sách của tác giả đã được xuất bản về các công cụ phân tích hệ thống và thiết kế hệ thống thông tin - BPwin và ERwin. (Maklakov S. BPwin và ERwin. CASE-công cụ để phát triển hệ thống thông tin. M: Dialog-MEPhI). Cuốn sách đã trải qua hai lần xuất bản và

Từ cuốn sách Công nghệ XSLT tác giả Valikov Alexey Nikolaevich

Lời nói đầu Cuốn sách này nói về điều gì? Thật khó để đánh giá quá cao tác động của những năm vừa qua đối với công nghệ thông tin sự xuất hiện và lan truyền của một ngôn ngữ có thể mở rộng Đánh dấu XML(từ tiếng Anh mở rộng Ngôn ngữ đánh dấu). Công nghệ XML đã được ứng dụng trong nhiều lĩnh vực và

Từ cuốn sách Kỹ thuật tạo nội thất theo nhiều phong cách khác nhau tác giả Timofeev S. M.

Lời nói đầu 3ds Max - rất chương trình phổ biếnđể tạo ra các dự án nội thất. Chương trình cung cấp rất nhiều cơ hội để tạo ra một bức tranh chân thực về nội thất trong tương lai, cho phép bạn truyền đạt một số khái niệm thiết kế cho cùng một căn phòng,

Từ sách 19 tội lỗi chết người đe dọa bảo mật phần mềm bởi Howard Michael

Lời nói đầu Lý thuyết máy tính dựa trên giả định rằng máy móc hoạt động một cách xác định. Chúng ta thường mong đợi một chiếc máy tính hoạt động theo cách chúng ta đã lập trình. Trên thực tế, đây chỉ là giả định gần đúng. Máy tính hiện đại tổng quan

Từ cuốn sách Cách cho voi ăn, hay những bước đầu tiên để tự tổ chức với Evernote của Sultanov Gani

Lời nói đầu Cuốn sách dành riêng cho hệ thống quản lý công việc và thu thập thông tin bằng dịch vụ Evernote Dưới đây là những gì viết về cuốn sách nhỏ này trên blog chính thức của Evernote: “Cuốn sách sẽ đặc biệt thú vị đối với những ai đã để mắt đến nó từ lâu. Phương pháp GTD nâng cao hiệu quả cá nhân

Từ cuốn sách Giới thiệu về Mật mã học tác giả Zimmermann Philip

Lời nói đầu Mật mã học là một chủ đề thường gặp trong truyện tranh thiếu nhi và truyện gián điệp. Trẻ em đã từng thu thập nhãn Ovaltine® để nhận được Chiếc nhẫn giải mã bí mật của Captain Midnight. Hầu như tất cả mọi người đều đã xem một bộ phim truyền hình về một quý ông kín đáo mặc bộ vest với

Từ cuốn sách iOS. Kỹ thuật lập trình tác giả Nahavandipur Vandad

Lời nói đầu Ấn bản này của cuốn sách không chỉ là một phiên bản mở rộng mà còn là một phiên bản sửa đổi hoàn toàn của ấn bản trước. Mọi thứ đã thay đổi trong iOS 7: vẻ bề ngoài và mặt chức năng hệ điều hành, cách sử dụng thiết bị iOS của chúng tôi và quan trọng nhất là các nguyên tắc

Từ cuốn sách Lập trình viên cuồng tín của Chad Fowler

Lời nói đầu Tôi chắc chắn rằng có điều gì đó phi thường trong mỗi chúng ta, nhưng chúng ta phải dành rất nhiều thời gian để tìm hiểu điều gì thực sự quan trọng, cố gắng rút ra điều đó từ chính mình. Bạn không thể trở nên phi thường nếu bạn không yêu môi trường, công cụ, lĩnh vực của mình.

Sử dụng hiệu quả STL và các mẫu

Serge Satsky

Giới thiệu

Với sự trợ giúp của các máy trạng thái hữu hạn (sau đây gọi đơn giản là automata), bạn có thể giải quyết thành công nhiều loại vấn đề. Tình trạng này đã được chú ý từ lâu nên trong các tài liệu về thiết kế phần mềm thường bàn luận về chủ đề sử dụng automata (, ,). Tuy nhiên, trong quá trình lập mô hình, máy được xem từ một góc độ khác cấp độ cao hơn điều này được thực hiện tại thời điểm thực hiện bằng cách sử dụng ngôn ngữ cụ thể lập trình.

Lần cuối cùng Tạp chí người dùng C/C++ đề cập đến vấn đề thiết kế Máy trạng thái hữu hạn là vào số tháng 5 năm 2000 (). Số này đăng một bài viết của David Lafreniere, trong đó tác giả mô tả cách tiếp cận mà ông đã sử dụng. Đã nhiều thời gian trôi qua kể từ đó và bài viết này sẽ cố gắng thực hiện một cách tiếp cận khác để thiết kế máy trạng thái hữu hạn tính xu hướng hiện đại trong thiết kế phần mềm.

Để thuận tiện, hãy xem xét một ví dụ đơn giản sẽ được sử dụng dưới đây. Giả sử bạn cần xác định xem chuỗi ký tự đầu vào là số nguyên, mã định danh hợp lệ hay chuỗi không hợp lệ. Theo mã định danh hợp lệ, chúng tôi muốn nói đến những mã định danh bắt đầu bằng một chữ cái và sau đó chứa các chữ cái và “/” hoặc số. Máy sẽ giúp giải quyết vấn đề được hiển thị trong Hình 1. Hình này sử dụng ký hiệu UML (Ngôn ngữ mô hình hóa thống nhất).

Hình 1. Một máy tự động cho phép bạn tìm hiểu chuỗi đầu vào là gì.

Cần lưu ý rằng có nhiều nguồn ban tặng cho một cỗ máy như vậy những thuộc tính khác nhau. Nhà vô địch xét về số lượng có lẽ là UML(). Tại đây bạn có thể tìm thấy các sự kiện bị trì hoãn, chuyển tiếp nội bộ, trình kích hoạt sự kiện với các tham số, điều kiện bổ sung chuyển tiếp (điều kiện bảo vệ), chức năng nhập (hành động nhập), chức năng thoát (hành động thoát), sự kiện hẹn giờ, v.v. Tuy nhiên, ở đây, để đơn giản cho việc trình bày, chúng ta sẽ bỏ qua các thuộc tính bổ sung (chúng ta sẽ quay lại một số thuộc tính sau) và tập trung vào một mô hình đơn giản trong đó có các trạng thái, sự kiện và chuyển tiếp giữa các trạng thái.

TRÊN khoảnh khắc này tất cả những gì chúng tôi có là một mô hình trực quan và dễ làm. Làm thế nào bây giờ chúng ta có thể chuyển từ nó sang mã C++? Cách đơn giản nhất để triển khai nó là một tập hợp các câu lệnh if ở dạng này hay dạng khác. Ví dụ:

chuyển đổi (Trạng thái hiện tại)

trường hợp State1: if (CurrentEvent == Event1)

nếu (Sự kiện hiện tại == Sự kiện2)

trường hợp Trạng thái 2:....

Không quá đồ họa, phải không? Bây giờ hãy tưởng tượng rằng chúng ta có hàng chục sự kiện và hàng chục trạng thái. Loại mã này rất khó xem. Các vấn đề đặc biệt nghiêm trọng phát sinh trong quá trình bảo trì mã, khi bạn cần quay lại mã đó sau một vài tháng và sửa chữa.

Một cách triển khai khả thi khác là một tập hợp các hàm, mỗi hàm đại diện cho một trạng thái. Hàm như vậy sẽ có thể trả về một con trỏ tới hàm tương ứng với trạng thái mới của máy. Việc triển khai này cũng không làm cho mã dễ bảo trì hơn.

Hãy tiếp cận vấn đề từ một góc độ hơi khác. Hình ảnh tốt, nhưng ở dạng ban đầu, nó không thể được chuyển sang văn bản gốc. Điều này có nghĩa là ngay cả khi tìm thấy giải pháp, nó sẽ là thứ gì đó trung gian giữa hình ảnh và văn bản thông thường.

Phương pháp triển khai máy

Biểu diễn trung gian như vậy của máy có thể là một cái bàn. Ví dụ, phương pháp này đã được biết đến từ lâu. Hãy tạo một bảng chuyển tiếp cho máy của chúng ta (Bảng 1).

Bảng 1.

Ở đây hàng đầu tiên liệt kê các trạng thái có thể xảy ra và cột đầu tiên liệt kê các sự kiện có thể xảy ra. Tại các giao lộ, các trạng thái mà quá trình chuyển đổi phải diễn ra sẽ được chỉ định.

Việc biểu diễn một máy tự động dưới dạng một bảng rõ ràng hơn nhiều so với cách biểu diễn “bị nhòe” của cùng một máy tự động dưới dạng câu điều kiện hoặc các hàm chuyển tiếp. Bây giờ bạn có thể thử dịch bảng thành mã.

Giả sử rằng chúng ta đã dịch được bảng thành mã. Bạn muốn mã này trông như thế nào? Hãy để chúng tôi xây dựng các yêu cầu cho nó ():

Phần mô tả về máy (bảng đọc) nên tập trung ở một nơi. Điều này sẽ làm cho máy dễ đọc, hiểu và sửa đổi.

Việc biểu diễn máy tự động phải là loại an toàn.

Không nên có hạn chế về số lượng trạng thái và sự kiện.

Chúng tôi muốn biểu diễn các sự kiện và trạng thái dưới dạng các kiểu trừu tượng do người dùng xác định.

Nếu có thể, tôi muốn làm cho chiếc máy trở nên linh hoạt và dễ dàng mở rộng.

Nếu có thể, tôi muốn kiểm tra mô tả của máy.

Nếu có thể, chúng tôi muốn loại trừ việc sử dụng máy không đúng cách.

Yêu cầu 1 và 7 có nghĩa là sẽ tốt hơn nếu đặt toàn bộ mô tả của máy vào hàm tạo. Trong hàm tạo, cần kiểm tra tính đúng đắn của mô tả - yêu cầu 6.

Yêu cầu 2 có nghĩa là không được sử dụng thao tác không an toàn như reinterpret_cast.

Chúng ta sẽ nói về yêu cầu 5 sau, nhưng bây giờ hãy thảo luận về yêu cầu 3. B trường hợp chung số lượng trạng thái có thể có (nghĩa là số lượng cột trong bảng) là không xác định. Số lượng sự kiện (tức là số lượng hàng trong bảng) cũng không xác định. Hóa ra hàm tạo của lớp, sẽ là một máy tự động, có số lượng đối số thay đổi. Thoạt nhìn, vấn đề này có vẻ dễ giải quyết bằng cách sử dụng các hàm ngôn ngữ C va_arg(), va_copy(), va_end() và va_start()(). Tuy nhiên, không phải tất cả đều đơn giản như vậy. Đối với các hàm này, cần phải cung cấp các dấu hiệu ở cuối danh sách và trong trường hợp của chúng tôi, số phần tử trong hàng và cột là không xác định. Không nên chỉ định kích thước. Ngoài ra, các chức năng này được đảm bảo chỉ hoạt động đối với POD (Dữ liệu cũ thuần túy) và đối với các loại tùy ý rắc rối có thể xảy ra.

Hãy tiếp cận từ phía bên kia. Hãy viết cách chúng ta muốn xem hàm tạo của máy:

Khi gọi hàm tạo theo cách này, bằng cách định dạng văn bản bằng phông chữ đơn cách, mô tả về máy có thể có dạng bảng. Hãy tưởng tượng:

SFiniteStateMachine A(

“trống”, “số”, “mã định danh”, “không xác định”,

chữ cái, “số nhận dạng”, “không xác định”, “số nhận dạng”, “không xác định”,

chữ số, “số”, “số”, “mã định danh”, “không xác định”

Trạng thái bắt đầu rất đơn giản: nó chỉ là một đối tượng của một lớp đại diện cho trạng thái đó. Với một danh sách các trạng thái và thậm chí hơn thế nữa với một danh sách các chuyển đổi, mọi thứ trở nên phức tạp hơn. Không thể liệt kê các trạng thái được phân tách bằng dấu phẩy. Hơn nữa, sẽ thuận tiện cho SFiniteStateMachine có số lượng đối số cố định. Hóa ra điều này là có thể. Rốt cuộc, chúng ta có thể tạo các đối tượng tạm thời, mỗi đối tượng sẽ xử lý danh sách riêng của nó.

Chúng ta hãy nhìn vào danh sách các tiểu bang. Vấn đề tương tự vẫn còn ở đây - số lượng trạng thái không xác định. Quá tải toán tử và hàm tạo mặc định có thể giúp giải quyết vấn đề này. Vẫn không thể liệt kê các đối số được phân tách bằng dấu phẩy, nhưng một dấu phân cách khác sẽ phù hợp thay vì dấu phẩy. Một dải phân cách như vậy có thể là<<, то есть обработку списка состояний можно записать так:

Hãy làm tương tự với danh sách chuyển tiếp cho một sự kiện. Sự khác biệt duy nhất là mỗi danh sách chuyển tiếp có thêm một thuộc tính - một sự kiện mô tả các chuyển đổi. Hàm tạo STransitionsProxy sẽ nhận một đối số: sự kiện và toán tử quá tải<< будет принимать состояния.

Toán tử quá tải<< проверит, что сначала идет список состояний, что список состояний только один, что в списках переходов нет повторяющихся событий и в переходах указаны только состояния, указанные в списке состояний. operator<< также проверит, что количество состояний в списках переходов равно количеству состояний в списке состояний. В результате конструктор SFiniteStateMachine будет выглядеть так:

Hàm tạo SFiniteStateMachine sẽ có nhiệm vụ kiểm tra trạng thái ban đầu. Nó phải có trong danh sách các tiểu bang.

Bằng cách định dạng văn bản, chúng ta đã cố gắng cung cấp cho các đối số của hàm tạo hình dạng của một bảng. Tuy nhiên, đó không phải là tất cả. Khi mô tả máy, mọi chi tiết liên quan đến mẫu đều bị lược bỏ. Trong thực tế, điều này có nghĩa là trong quá trình xây dựng, bạn cũng sẽ phải chỉ định các loại, điều này sẽ tiếp tục "xả rác" văn bản. Bất chấp các vấn đề liên quan đến bộ tiền xử lý, nó sẽ giúp ích ở đây. Các đối số của hàm tạo sẽ trông giống như thế này:

FSMBEGIN(“trống”)

FSMSTATES “trống”<< “number” << “identifier” << “unknown”

FSMEVENT(chữ cái) “định danh”<< “unknown” << “identifier” << “unknown”

FSMEVENT(chữ số) “số”<< “number” << “identifier” << “unknown”

Bản ghi này đã được chấp nhận để sử dụng hàng ngày.

Chi tiết triển khai

Việc triển khai phải bao gồm một số yếu tố hỗ trợ, đặc biệt là các trường hợp ngoại lệ. Máy sẽ đưa ra chúng trong trường hợp có lỗi trong mô tả trạng thái và chuyển tiếp. Khi phát triển lớp ngoại lệ của riêng mình, bạn có thể sử dụng tính kế thừa từ lớp ngoại lệ tiêu chuẩn. Điều này sẽ giúp bạn chỉ có thể chỉ định một tham chiếu đến lớp ngoại lệ tiêu chuẩn cơ bản trong khối bắt. Bạn có thể định nghĩa lớp ngoại lệ của mình như thế này:

Hãy quay trở lại với các nhà thiết kế. Vì chúng xử lý các danh sách có độ dài thay đổi nên việc sử dụng các vùng chứa do thư viện STL() cung cấp để lưu trữ các phần tử là điều hợp lý. Để lưu trữ danh sách một chiều, chúng ta sẽ sử dụng vùng chứa vectơ và đối với bảng chuyển tiếp, vectơ gồm các vectơ:

Vì vùng chứa vectơ hỗ trợ toán tử, nên bạn có thể sử dụng cấu trúc tương tự trong bảng chuyển đổi để tìm trạng thái mà bạn muốn chuyển đổi sang:

Tất nhiên, lớp automaton sẽ phải có chức năng nhận và xử lý sự kiện. Có hai lựa chọn. Đầu tiên là một hàm, thứ hai là quá tải của một toán tử. Để tăng thêm tính linh hoạt, chúng tôi triển khai cả hai tùy chọn:

Câu hỏi vẫn là: phải làm gì nếu một sự kiện xảy ra mà máy không có mô tả chuyển tiếp? Các tùy chọn chỉ đơn giản là bỏ qua một sự kiện như vậy, đưa ra một ngoại lệ hoặc thực hiện điều gì đó do người dùng xác định. Hãy sử dụng ý tưởng về chiến lược () và đưa vào trong số các đối số mẫu một hàm hàm sẽ xác định chiến lược hành vi mong muốn. Cách tiếp cận này hoàn toàn phù hợp với yêu cầu 5. Trong trường hợp này, bạn có thể đặt chiến lược mặc định - ví dụ: đưa ra một ngoại lệ. Bây giờ tiêu đề mẫu trông như thế này:

Nếu bạn cần các hành động khác, bạn luôn có thể viết functor của riêng mình theo hình ảnh và chân dung của SIgnoreStrategy rồi chuyển nó vào mẫu.

Nhiều nguồn mô tả máy trạng thái hữu hạn đề cập đến khả năng gọi các hàm khi vào và thoát trạng thái. Khả năng này có thể dễ dàng được cung cấp bằng cách sử dụng cùng một cách tiếp cận chiến lược. Thật thuận tiện khi xác định các hàm nhập và thoát trạng thái cho một lớp đại diện cho một trạng thái cụ thể. Ghi nhớ yêu cầu 5, hãy cung cấp khả năng quản lý linh hoạt tính năng này. Giả sử rằng các hàm lớp trạng thái sẽ được gọi là OnEnter và OnExit, chúng ta có thể viết một số functor làm sẵn: một hàm không gọi cả hàm, một hàm chỉ gọi OnEnter, một hàm chỉ gọi OnExit và một hàm gọi cả hai hàm.

bản mẫu

lớp SEmptyFunctor

(trở lại;)

bản mẫu

lớp SOnEnterFunctor

toán tử void nội tuyến() (SState & From, const SEvent & Event, SState & To)

( To.OnEnter(Từ, Sự kiện); )

bản mẫu

lớp SOnExitFunctor

toán tử void nội tuyến() (SState & From, const SEvent & Event, SState & To)

( From.OnExit(Sự kiện, Đến); )

bản mẫu

lớp SOnMoveFunctor

toán tử void nội tuyến() (SState & From, const SEvent & Event, SState & To)

( From.OnExit(Sự kiện, Đến); To.OnEnter(Từ, Sự kiện); )

Chiến lược mặc định (không gọi bất kỳ hàm nào) có thể được truyền dưới dạng đối số mẫu. Chiến lược gọi hàm có thể thay đổi thường xuyên hơn chiến lược xử lý một sự kiện chưa biết. Do đó, sẽ hợp lý nếu đặt nó vào danh sách các đối số trước chiến lược phản ứng với một sự kiện chưa xác định:

bản mẫu

lớp SFunctor = SEmptyFunctor ,

lớp SUnknownEventStrategy = SThrowStrategy >

lớp SFiniteStateMachine (... );

Một vấn đề khác với các sự kiện là một sự kiện có thể được tạo bên trong một hàm được gọi khi một trạng thái được thoát hoặc được nhập. Để xử lý các sự kiện như vậy, bạn cần thiết kế hàm nhận sự kiện cho phù hợp. Có tính đến các sự kiện “nội bộ” như vậy, cần phải cung cấp một hàng đợi trong đó các sự kiện sẽ được đặt. Mã xử lý chuyển tiếp sẽ phải thực hiện việc này cho đến khi hàng đợi trống. Chúng tôi sẽ sử dụng deque từ STL làm vùng chứa phù hợp để lưu trữ các sự kiện. Vì chúng ta chỉ cần chèn các phần tử ở đầu và loại trừ ở cuối vùng chứa, không cần truy cập ngẫu nhiên nên vùng chứa deque là phù hợp nhất.

Còn lại rất ít. Đôi khi bạn cần khôi phục máy về trạng thái ban đầu. Như trong trường hợp sự kiện, chúng tôi cung cấp hai tùy chọn: hàm thông thường và toán tử quá tải<<. Для перегруженного operator << нужно определить специальный манипулятор:

Kết quả hoạt động của máy là trạng thái mà nó đã chuyển sang. Để có được trạng thái hiện tại, chúng ta sẽ viết một hàm và nạp chồng toán tử đầu ra vào luồng của lớp automaton:

Như đã đề cập, một số macro được xác định để giảm thời gian gõ và khả năng đọc. Chúng yêu cầu các thay thế được xác định trước cho các loại sự kiện và trạng thái. Yêu cầu này là do việc sử dụng các chỉ thị tiền xử lý lồng nhau là không thể. Mẫu sử dụng các lớp Proxy, cũng cần thông tin về loại. Vì vậy, để sử dụng macro bạn sẽ phải làm như sau:

#define chuỗi FSMStateType // Kiểu trạng thái

#define FSMEventType int // Loại sự kiện

#undef FSMStateType

#undef FSMEEventType

Có một giải pháp thay thế: chỉ định đầy đủ tất cả các loại.

Tất cả những gì còn lại là đặt mẫu vào không gian tên. Sau đó bạn có thể sử dụng nó.

Ví dụ về việc sử dụng mẫu

Hãy viết code để giải quyết vấn đề đặt ra ở đầu bài viết.

#bao gồm

#bao gồm

sử dụng không gian tên std;

#include "FiniteStateMachine.h"

sử dụng không gian tên FSM;

// Xác định kiểu cho sự kiện

enum Sự kiện ( thư = 0, chữ số = 1 );

int main(int argc, char ** argv)

#define chuỗi FSMStateType

#define FSMEventType Sự kiện

SFiniteTrạng tháiMáy< StateType,

SEmptyFunctor ,

SThrowChiến lược

FSMBEGIN("trống")

FSMSTATES "trống"<< «number» << «identifier» << «unknown»

FSMEVENT(chữ cái) "định danh"<< «unknown» << «identifier» << «unknown»

FSMEVENT(chữ số) "số"<< «number» << «identifier» << «unknown»

#undef FSMStateType

#undef FSMEEventType

cout<< «StartState is: » << MyMachine << endl;

Máy của tôi<< digit << digit << letter;

cout<< «The "unknown" state is expected. Current state is: » << MyMachine << endl;

// Lưu ý: bắt buộc phải có dấu ngoặc đơn ở dòng tiếp theo. Họ sẽ cung cấp

// đúng thứ tự thực hiện câu lệnh

cout<< «Reset the machine. Current state is: » << (MyMachine << ResetMachine) << endl;

Máy của tôi<< letter << digit << letter;

cout<< «The "identifier" state is expected. Current state is: » << MyMachine << endl;

Ví dụ này cố tình bỏ qua các chi tiết như xử lý ngoại lệ và giới thiệu các hàm được gọi khi vào và thoát khỏi một trạng thái. Để thể hiện khả năng xác định chiến lược người dùng, hàm tạo MyMachine chỉ định tất cả các tham số, bao gồm cả các tham số mặc định.

Yêu cầu đối với ứng dụng khách

Yêu cầu rất ít. Các lớp sự kiện và trạng thái phải có toán tử==, toán tử= và hàm tạo bản sao được xác định. operator== được sử dụng để tìm kiếm các sự kiện và trạng thái trong danh sách bằng thuật toán tìm STL. operator= được sử dụng khi sao chép các phần tử danh sách. Hàm tạo sao chép được sử dụng khi khởi tạo danh sách và các phần tử khác.

Nếu máy khách sử dụng functor được cung cấp để gọi các hàm nhập và thoát thì lớp trạng thái phải triển khai các hàm tương ứng: OnExit và OnEnter.

Ưu điểm và nhược điểm của giải pháp đề xuất

Thuận lợi:

Mẫu được gõ mạnh. Điều này có nghĩa là mã được viết không chính xác sẽ không được trình biên dịch chấp nhận và lỗi sẽ không đạt đến thời gian chạy của chương trình.

Các khái niệm về trạng thái và sự kiện đã được mở rộng. Bây giờ đây là các lớp tùy ý được viết bởi người dùng.

Toán tử reinterpret_cast không được sử dụng<…>, có thể dẫn đến kết quả không chính xác.

Toàn bộ mô tả về máy đều tập trung ở một nơi. Không có mối liên hệ nào với trình tự mô tả các phản ứng trước các sự kiện.

Tính linh hoạt của hành vi được xác định bởi các hàm chức năng do người dùng xác định. Một tập hợp các functor làm sẵn được cung cấp.

Có thể tự động tạo mô tả về máy trạng thái hữu hạn. Ví dụ: bạn có thể tạo phiên bản của các lớp Proxy, đọc mô tả máy từ một tệp và sau đó tạo phiên bản SFiniteStateMachine.

Không có thao tác nào để tạo và xóa đối tượng bằng toán tử mới và xóa.

Không có yêu cầu nào đối với các loại trạng thái và sự kiện (ngoài khả năng so sánh chúng).

Sai sót:

Có rất nhiều thao tác sao chép khi tạo máy. Tuy nhiên, nhược điểm này được bù đắp một phần bởi thông thường máy được tạo ra một lần và sử dụng nhiều lần.

Bạn cần viết hai chỉ thị tiền xử lý hoặc sử dụng tiền tố dài. Tuy nhiên, đây chỉ là vấn đề đánh máy.

Cá nhân tôi sẵn sàng đưa ra danh sách ngắn những nhược điểm này vì lợi ích thu được.

Những cách có thể để cải thiện mẫu

Người đọc tinh ý sẽ nhận thấy rằng bạn có thể tăng tính linh hoạt và hiệu suất của mẫu. Danh sách sau đây nêu bật những cải tiến bề ngoài:

Bạn có thể bỏ qua lớp trung gian SFiniteStateMachineProxy. Điều này sẽ tiết kiệm chi phí sao chép nhưng sẽ gây ra nguy cơ sử dụng mẫu không chính xác.

Bạn có thể giới thiệu các trình điều khiển sẽ cho phép bạn chỉ ra rõ ràng khi mô tả các chuyển đổi mà nên bỏ qua hoặc tạo ra một ngoại lệ khi chúng xảy ra.

An toàn chủ đề

Mẫu sử dụng bộ chứa STL, có thể gây ra sự cố trong môi trường đa luồng. Vì khi thiết kế mẫu, mục tiêu là phát triển một giải pháp độc lập với nền tảng nên không có công cụ đồng bộ hóa nào trong mẫu. Sự hiện diện của các công cụ đồng bộ hóa, như đã biết, tùy thuộc vào tình huống, có thể vừa là lợi thế vừa là bất lợi. Nếu không cần thiết, sự hiện diện của chúng sẽ chỉ tạo thêm chi phí. Việc thêm các công cụ đồng bộ hóa vào mẫu sẽ không khó đối với một nhà phát triển có kinh nghiệm.

Thư mục

Tạp chí người dùng C/C++, tháng 5 năm 2000

Booch G., Rumbaugh J., Jacobson I. Hướng dẫn sử dụng ngôn ngữ mô hình hóa thống nhất. Addison-Wesley, 2001

Meyers S. STL hiệu quả. Addison-Wesley, 2001

Alexandrescu A. Thiết kế C++ hiện đại. Addison-Wesley, 2002

Lewis P., Rosenkrantz D., Stearns R. Lý thuyết thiết kế trình biên dịch. Addison-Wesley, 1976

Tài liệu tham khảo dành cho lập trình viên Schildt H. C/C++. Phiên bản thứ hai. Williams, 2000

Meyers S. C++ hiệu quả. Phiên bản thứ hai. Addison-Wesley, 1998 và C++ hiệu quả hơn. Addison-Wesley, 1996

Sutter G. C++ đặc biệt. Addison-Wesley, 2002

Sử dụng STL hiệu quả

Lời nói đầu

“...Không có dải ruy băng nào trên đó cả! Không có lối tắt! Không có hộp và không có túi!”

Tiến sĩ Suess, Grinch đã đánh cắp Giáng sinh như thế nào

Lần đầu tiên tôi viết về STL (Thư viện mẫu tiêu chuẩn) vào năm 1995. Cuốn sách "C++ hiệu quả hơn" của tôi đã kết thúc với phần tổng quan ngắn gọn về thư viện. Nhưng điều này vẫn chưa đủ, và ngay sau đó tôi bắt đầu nhận được tin nhắn hỏi khi nào cuốn sách “STL hiệu quả” sẽ được viết.

Tôi đã phản đối ý tưởng này trong nhiều năm. Lúc đầu, tôi không có đủ kinh nghiệm về lập trình STL và không cho rằng có thể đưa ra lời khuyên. Nhưng thời gian trôi qua, vấn đề này đã được thay thế bằng vấn đề khác. Không còn nghi ngờ gì nữa, sự xuất hiện của thư viện có nghĩa là một bước đột phá trong lĩnh vực kiến ​​trúc có khả năng mở rộng hiệu quả, nhưng trong lĩnh vực này sử dụng STL gặp phải những vấn đề hoàn toàn thực tế mà không thể nhắm mắt làm ngơ. Việc điều chỉnh tất cả ngoại trừ các chương trình STL đơn giản nhất gặp nhiều vấn đề, không chỉ do sự khác biệt trong cách triển khai mà còn do các mức hỗ trợ mẫu trình biên dịch khác nhau. Sách giáo khoa về STL rất hiếm nên việc hiểu “Đạo của lập trình STL” không phải là một việc dễ dàng. Và ngay khi lập trình viên đối mặt với khó khăn này, một khó khăn khác lại nảy sinh - việc tìm kiếm tài liệu tham khảo đủ đầy đủ và chính xác. Ngay cả lỗi nhỏ nhất khi sử dụng STL cũng đi kèm với hàng loạt thông báo chẩn đoán trình biên dịch, độ dài của chúng lên tới vài nghìn ký tự và trong hầu hết các trường hợp, chúng là về các lớp, hàm và mẫu không được đề cập trong chương trình. Với tất cả sự tôn trọng dành cho STL và các nhà phát triển thư viện này, tôi đã do dự khi giới thiệu nó cho các lập trình viên cấp trung. Tôi không chắc chắn về STL Có thể sử dụng hiệu quả.

Sau đó tôi nhận thấy một điều đáng kinh ngạc. Bất chấp tất cả các vấn đề về chuyển và chất lượng tài liệu kém, bất chấp các thông báo của trình biên dịch giống như một mớ ký hiệu lộn xộn vô nghĩa, nhiều khách hàng của tôi vẫn làm việc với STL. Hơn nữa, họ không chỉ thử nghiệm thư viện mà còn sử dụng nó trong các phiên bản thương mại của chương trình của họ! Đó là một sự mặc khải đối với tôi. Tôi biết rằng các chương trình sử dụng STL có kiến ​​trúc tao nhã, nhưng bất kỳ thư viện nào mà lập trình viên sẵn sàng gặp khó khăn khi chuyển, tài liệu kém và thông báo lỗi khó hiểu đều phải có thứ gì đó hơn là kiến ​​trúc tốt. Ngày càng có nhiều lập trình viên chuyên nghiệp tin rằng ngay cả việc triển khai STL không tốt vẫn tốt hơn là không triển khai gì cả.

Hơn nữa, tôi biết rằng tình hình với STL sẽ được cải thiện. Các thư viện và trình biên dịch sẽ dần dần tiến gần hơn đến các yêu cầu của Tiêu chuẩn (đây là cách nó đã xảy ra), tài liệu chất lượng cao sẽ xuất hiện (xem danh sách tài liệu tham khảo ở trang 203) và chẩn đoán trình biên dịch sẽ trở nên dễ hiểu hơn (trong lĩnh vực này, tình huống còn nhiều điều đáng mong đợi, nhưng những khuyến nghị của Hội đồng 49 sẽ giúp bạn giải mã tin nhắn). Vì vậy, tôi quyết định đóng góp cho phong trào STL. Đây là cách cuốn sách này xuất hiện - 50 lời khuyên thiết thực về cách sử dụng STL trong C++.

Lúc đầu tôi định viết một cuốn sách vào nửa cuối năm 1999 và thậm chí còn phác thảo ra cấu trúc thô của nó. Nhưng sau đó kế hoạch thay đổi, tôi tạm dừng công việc viết cuốn sách và phát triển một khóa học giới thiệu về STL, khóa học này được dạy cho một số nhóm lập trình viên. Khoảng một năm sau, tôi quay lại cuốn sách và mở rộng tài liệu rất nhiều dựa trên những kinh nghiệm tôi có được khi giảng dạy. Trong cuốn sách, tôi đã cố gắng đề cập đến các khía cạnh thực tế của việc lập trình trong STL, đặc biệt quan trọng đối với các lập trình viên chuyên nghiệp.

Scott Douglas Meyers Stafford, Oregon Tháng 4 năm 2001

Sự nhìn nhận

Trong nhiều năm, tôi đã hiểu STL, phát triển khóa học và viết cuốn sách này, tôi đã nhận được sự giúp đỡ và hỗ trợ vô giá từ nhiều người. Tôi muốn đặc biệt cảm ơn Mark Rodgers, người đã hào phóng đề nghị xem lại các tài liệu khóa học ngay khi chúng được viết ra. Tôi đã học được nhiều điều về STL từ anh ấy hơn bất kỳ ai khác. Mark cũng từng là người biên tập kỹ thuật cho cuốn sách này, những nhận xét và bổ sung của anh ấy đã giúp cải thiện phần lớn tài liệu.

Một nguồn thông tin nổi bật khác là các diễn đàn Usenet; dành riêng cho ngôn ngữ C++, đặc biệt là comp.lang.c++.moderated (“clcm”), comp.std.c++ và microsoft.public.vc.stl. Trong hơn mười năm, những người tham dự hội nghị này và các hội nghị khác đã trả lời các câu hỏi của tôi và đặt ra những vấn đề mà tôi phải suy nghĩ. Tôi vô cùng biết ơn cộng đồng Usenet vì đã hỗ trợ phát triển cuốn sách này và các ấn phẩm C++ trước đây của tôi.

Sự hiểu biết của tôi về STL đã được hình thành qua một số ấn phẩm, trong đó ấn phẩm quan trọng nhất được liệt kê ở cuối cuốn sách. Tôi đặc biệt học được rất nhiều thông tin hữu ích từ tác phẩm “Thư viện chuẩn C++” của Josattis.

Những ý tưởng và quan sát tạo nên cuốn sách này chủ yếu là của các tác giả khác, mặc dù nó chứa đựng một số khám phá của riêng tôi. Tôi đã cố gắng hết sức để truy tìm nguồn gốc của tài liệu, nhưng nhiệm vụ này chắc chắn sẽ thất bại vì thông tin được thu thập từ nhiều nguồn trong một thời gian dài. Danh sách dưới đây vẫn chưa đầy đủ nhưng tôi không thể đưa ra điều gì tốt hơn. Xin lưu ý rằng danh sách này đề cập đến các nguồn mà tôi đã học được về một số ý tưởng và kỹ thuật nhất định chứ không phải những người khởi xướng chúng.

Trong Mục 1, lưu ý rằng vùng chứa nút cung cấp hỗ trợ tốt hơn cho ngữ nghĩa giao dịch xuất phát từ Phần 5.11.2 của Thư viện chuẩn C++. Ví dụ về việc sử dụng typedef khi thay đổi loại cấp phát bộ nhớ từ mẹo 2 đã được Mark Rogers đề xuất. Mẹo 5 được lấy cảm hứng từ bài báo "STL Gotchas" của Reeves. Mẹo 8 dựa trên mẹo 37 trong cuốn sách Exceptional C++ của Sutter và Kevlin Henney đã cung cấp thông tin quan trọng về các vấn đề gặp phải khi sử dụng vùng chứa auto_ptr . Trên Usenet, Matt Austem đã cung cấp các ví dụ về cách sử dụng bộ cấp phát bộ nhớ mà tôi đã đưa vào Mẹo 11. Mẹo 12 dựa trên tài liệu trên trang SGI STL về an toàn luồng. Thông tin về tính tham chiếu trong môi trường đa luồng từ mẹo 13 đến từ bài viết của Sutter. Ý tưởng cho mẹo 15 được lấy cảm hứng từ bài viết "Sử dụng chuỗi tiêu chuẩn trong thế giới thực, Phần 2" của Reeves. Phương pháp ghi dữ liệu trực tiếp trong vectơ r, được trình bày trong mẹo 16 do Mark Rogers đề xuất. Mẹo 17 bao gồm thông tin từ Usenet và được viết bởi Siemel Naran và Carl Barron. Mẹo 18 được lấy từ bài viết của Sutter "Khi nào một container không phải là một container?" . Đối với mẹo 20, Mark Rogers đã đề xuất ý tưởng chuyển đổi một con trỏ thành một đối tượng thông qua sự tham chiếu và Scott Lewandowski đã phát triển phiên bản DereferenceLess được trình bày. Mẹo 21 dựa trên bài đăng của Doug Harrison trên microsoft.public.vc.stl, nhưng quyết định giới hạn phạm vi của mẹo này đối với vấn đề bình đẳng là của riêng tôi. Mẹo 22 dựa trên bài viết "Tin tức thư viện tiêu chuẩn: bộ và bản đồ" của Sutter. Mẹo 23 được đề xuất bởi bài viết "Tại sao bạn không nên sử dụng tập hợp - và thay vào đó nên sử dụng cái gì"; kết luận của mẹo 26, nhưng mẹo ban đầu được nhắc nhở bởi quan sát của anh ấy rằng một số hàm chứa chỉ chấp nhận các đối số kiểu iterator . Mẹo 29 được lấy cảm hứng từ các cuộc thảo luận trên Usenet có sự tham gia của Matt Ostern và James Kanze; Tôi cũng bị ảnh hưởng bởi bài viết “Triển khai tinh vi các bộ chèn và trích xuất do người dùng xác định” của Klaus Kreft và Angelika Langer. Mẹo 30 dựa trên phần 5.4.2 trong cuốn sách Thư viện chuẩn C++ của Josattis. Trong Mẹo 31, Marco Dalla Gasperina đã đưa ra một ví dụ về cách sử dụng nth_element để tính trung vị và việc sử dụng thuật toán này để tìm phân vị được lấy trực tiếp từ phần 18.7.1 của Ngôn ngữ lập trình C++ của Stroustrup. Mẹo 32 được lấy cảm hứng từ phần 5.6.1 trong cuốn sách Thư viện chuẩn C++ của Josattis. Mẹo 35 được lấy cảm hứng từ bài viết "Cách thực hiện so sánh chuỗi không phân biệt chữ hoa chữ thường" của Austern và các bài đăng của James Kanze và John Potter đã giúp tôi hiểu rõ hơn những gì đang diễn ra. Việc triển khai copy_if trong Mục 36 được lấy từ Phần 18.6.1 của Ngôn ngữ lập trình C++ của Stroustrup. Mẹo 39 dựa trên các ấn phẩm của Josattis, người đầu tiên đề cập đến “các biến vị ngữ có trạng thái” trong cuốn sách “Thư viện chuẩn C++” và trong bài báo “Các biến vị ngữ so với các biến vị ngữ”. Đối tượng chức năng". Trong cuốn sách của mình, tôi sử dụng ví dụ của anh ấy và đề xuất giải pháp của anh ấy, mặc dù thuật ngữ “hàm thuần túy” là của tôi. Ở mẹo 41, Matt Ostern đã xác nhận những nghi ngờ của tôi về nguồn gốc của tên mem_fun và mem_fun_ref. Mẹo 42 xuất phát từ một bài giảng của Mark Rogers khi tôi vi phạm khuyến nghị của mẹo đó. Mark Rogers cũng đã nêu quan điểm trong Mục 44 rằng các tìm kiếm bên ngoài trong vùng chứa bản đồ và nhiều bản đồ sẽ phân tích cả hai thành phần của cặp, trong khi tìm kiếm theo hàm vùng chứa chỉ tính đến thành phần đầu tiên (khóa). Mẹo 45 sử dụng thông tin từ nhiều người đóng góp clem, bao gồm John Potter, Marcin Kasperski, Pete Becker, Dennis Yelle và David Abrahams. David Smallberg đã cho tôi ý tưởng sử dụng Equal_range để thực hiện tìm kiếm tương đương và đếm kết quả trong các vùng chứa tuần tự được sắp xếp. Andrei Alexandrescu đã giúp hiểu các điều kiện của vấn đề "link to link" được đề cập ở mẹo 50; Ví dụ được đưa ra trong cuốn sách dựa trên một ví dụ tương tự của Mark Rogers lấy từ trang web Boost.

Sử dụng vùng chứa vector STL. Hiệu suất vectơ
Việc sử dụng các thùng chứa thư viện chuẩn C++ luôn được thúc đẩy bởi sự đơn giản, tiện lợi và hiệu suất. Nhưng giống như bất kỳ “công cụ” nào, nó phải được sử dụng đúng cách, bởi vì một công cụ tốt và hiệu quả nếu rơi vào tay kẻ xấu có thể trở nên vô dụng hoặc không hiệu quả. Trong bài viết ngắn này, tôi sẽ cho bạn biết cách sử dụng nó hiệu quả nhất có thể và những vấn đề cũng như cạm bẫy nào có thể phát sinh khi bạn gặp nó lần đầu.

Hãy bắt đầu lại từ đầu
STL - Thư viện mẫu chuẩn. Nghĩa là, mọi thứ được thể hiện bằng (các) mẫu trong thư viện chuẩn đều là STL. Nhưng phần lớn, STL được coi là vùng chứa, thuật toán và trình vòng lặp.
STL từ lâu đã được đưa vào thư viện C++ tiêu chuẩn, nhưng vẫn không phải ai cũng sử dụng nó một cách đầy đủ, chủ yếu là do không biết đến sự tồn tại của một số lớp mẫu nhất định.

Và vì vậy hãy quay trở lại cụ thể với vectơ.
Vùng chứa vectơ giống như một mảng có thể chứa bất kỳ loại tích hợp sẵn hoặc do người dùng xác định. Nhưng so với mảng tích hợp, nó có một số lợi thế.

Anh ấy biết kích thước của chính mình (phương thức size())
- Bạn có thể dễ dàng thay đổi kích thước (thêm, bớt phần tử) trong quá trình thực hiện
- Khi xóa hay dọn dẹp nó gọi class hủy (à, ưu điểm này còn gây tranh cãi =))

Chúng ta hãy đi qua các phương pháp chính.

    push_back(element) - thêm một phần tử vào cuối vectơ
    pop_back(element) - xóa phần tử cuối cùng của vectơ
    Insert(***) - ba tùy chọn (tải lại phương thức) để chèn vào bất kỳ khu vực nào trong vectơ, tham số đầu tiên là vị trí chèn được cung cấp cho các trình vòng lặp, phần còn lại biểu thị một vùng chứa hoặc một số lượng và một vùng chứa hoặc một cặp các vòng lặp chỉ ra vị trí nào từ vùng chứa khác lấy dữ liệu.
    erase(iterator or iterator from, and to) - xóa một phần tử hoặc chuỗi các phần tử khỏi một vectơ
    Begin() - trả về một iterator trỏ đến phần đầu của bộ sưu tập.
    end() - trả về một iterator trỏ đến cuối bộ sưu tập. Đồng thời, anh ta không chỉ vào yếu tố cuối cùng mà chỉ vào yếu tố tưởng tượng đằng sau yếu tố cuối cùng.
    at(index) là một phương thức truy cập vào các phần tử của một bộ sưu tập, không giống như toán tử, nó kiểm tra việc vượt ra ngoài ranh giới của bộ sưu tập và nếu vậy, sẽ tạo ra một ngoại lệ.
    clear() - xóa tất cả các thành phần của bộ sưu tập và nếu nó chứa các đối tượng lớp, hãy gọi hàm hủy của chúng. Nhưng nếu có con trỏ tới đối tượng thì bạn sẽ bị rò rỉ bộ nhớ (memory Leak =))), nên sẽ không có ai gọi delete cho bạn đâu.
Đã đến lúc xem nó hoạt động!

Khi lặp qua một vectơ thông qua các trình vòng lặp, bạn cần rèn luyện bản thân để viết phần tăng trước( ++nó ), do đó, ông Hiệu quả hơn.

Tạo một vectơ tĩnh:

Trường hợp phổ biến nhất của vấn đề khi tạo một vectơ tĩnh là tạo nó trong một lớp.
Để tạo một vectơ tĩnh trong một lớp, bạn cần mô tả nó bằng .h và định nghĩa nó trong .cpp. Trong trường hợp này, tôi đặt mọi thứ vào một tệp, chỉ vì mục đích đơn giản. Bằng cách này, bạn không chỉ có thể tạo một vectơ tĩnh mà còn có thể tạo bất kỳ vùng chứa tĩnh nào khác.

Bây giờ về hiệu quả

Một vectơ có hiệu quả trong trường hợp bạn cần một vùng chứa để bạn tích lũy các phần tử. Tức là thêm vào. Một vectơ có hiệu quả khi được thêm vào cuối bằng push_back() và khi bị xóa khỏi cuối bằng pop_back().
Khi chèn hoặc xóa ở một vị trí tùy ý (các phương thứcinsert() và eras()), hiệu suất vector kém hơn so với danh sách ( danh sách) hoặc hàng đợi hai chiều( deque). Điều này là do thực tế là vectơ lưu trữ dữ liệu trong bộ nhớ tuần tự, cho phép truy cập ngẫu nhiên nhanh chóng và khả năng sử dụng vectơ như một mảng thông thường. Ví dụ, trong các chức năng tương tự OpenGL Thay vì con trỏ tới mảng C, bạn có thể chỉ định &vector_name.
Một vectơ không chỉ có kích thước (size()) mà còn có dung lượng (capacity()), dung lượng là số phần tử tối đa mà khi được thêm vào sẽ không khiến bộ đệm bên trong bị phân phối lại. Nếu vượt quá giá trị này, vectơ sẽ phân bổ một bộ đệm bên trong mới (bộ cấp phát) và sao chép tất cả các phần tử từ bộ đệm cũ sang bộ đệm mới, đồng thời xóa khỏi bộ đệm cũ. Nghĩa là, nếu chúng ta lưu trữ các đối tượng lớp lớn trong đó thì thao tác này sẽ khá tốn kém. Điều này sẽ được “cảm nhận” đặc biệt sâu sắc trên các vật thể lớn có hàm hủy phức tạp.
Dung lượng được xác định bằng cách triển khai chính thư viện tiêu chuẩn.

Nếu bạn lưu trữ con trỏ tới các đối tượng trong một vectơ thì điều này sẽ làm tăng đáng kể hiệu quả lưu trữ trong một vectơ, đặc biệt là các đối tượng lớn.
Việc lưu trữ các đối tượng nhỏ hoặc các kiểu có sẵn trong một vectơ khá hiệu quả.

Phần kết luận
Nếu bạn không có ý định loại bỏ các phần tử vùng chứa thường xuyên và bạn không cần chèn các phần tử ở đầu và giữa. Và bạn sẽ lưu trữ các đối tượng nhỏ, các loại có sẵn hoặc con trỏ tới bất kỳ đối tượng nào (lớn hoặc không lớn lắm =))). Tốt hơn hết bạn nên ưu tiên một vectơ và ghi nhớ những thao tác được thực hiện với nó, những gì chúng làm, bên trong nó, cùng những thứ khác. Và cái nào trong số chúng sẽ không quá đắt.

Bạn có thích bài viết? Lưu lại để về nghiên cứu tài liệu nhé!