Làm thế nào để tránh các biến toàn cầu c ++
Các biến toàn cục có thể truy cập được từ mọi nơi khiến chúng thuận tiện và hữu ích nhưng cũng nguy hiểm vì chúng có thể bị lạm dụng Show
Người ta có thể lập luận rằng chúng cho phép bạn chuyển hoặc truy cập dữ liệu qua các phạm vi hoặc lớp một cách dễ dàng, có thể hữu ích trong các ứng dụng nhúng với… Cấu trúc lớp học của bạn hơi khó hiểu. Đối với tôi, có vẻ như (các) giá trị int thực sự có thể thuộc về A và sau đó các phiên bản B và C đề cập đến một phiên bản của A (trong hàm tạo). [(Các) giá trị trong A sau đó phải ở chế độ riêng tư với trình truy cập 'get'. ] Nếu đây không phải là trường hợp và bạn thực sự cần cấu trúc như được mô tả, thì hàm tạo C có lẽ nên chấp nhận một tham chiếu đến một thể hiện B và B nên có một bộ truy cập 'set' cho giá trị bên trong của nó. Cả giá trị bên trong của B và C phải có quyền truy cập riêng tư (hoặc có thể/được cho là được bảo vệ) và có bộ truy cập đặt/nhận. Bạn không nên cho phép truy cập công khai vào những thứ này và truy cập chúng trực tiếp từ A Quyết định nơi một biến thuộc về không nên dựa trên "sự dễ dàng truy cập" mà dựa trên sự liên kết thực tế. Bạn đã không chỉ rõ những biến cục bộ này dùng để làm gì và chúng mô tả thuộc tính nào, nhưng cốt lõi của việc tránh các biến toàn cục là nhận ra rằng hầu hết mọi biến đều mô tả một số loại thuộc tính hoặc trạng thái của một số loại đối tượng, và do đó nên là . (và bạn nên tạo một lớp cho đối tượng đó nếu bạn chưa tạo) Khả năng tiếp cận thực sự chỉ là một suy nghĩ sau. Ví dụ: nếu bạn có một biến mô tả thuộc tính của B và bạn cần truy cập thông tin này cho các hoạt động cụ thể trong A và C, thì hãy chuyển thuộc tính đó làm tham số hàm hoặc cung cấp phương thức để đọc giá trị của biến này Chắc chắn có những ngoại lệ đối với 'quy tắc' đã đề cập ở trên. Nhưng nó thực sự hữu ích nếu bạn xem xét chính xác những gì một biến nhất định mô tả. OTOH, nếu mục đích của biến cục bộ đó không thể được mô tả dễ dàng, thì điều này có thể là do sử dụng lại biến; . Có một bài viết gần đây về lý do tại sao bạn không nên tái chế các biến cục bộ[^] và nó cũng áp dụng cho các biến toàn cục. Có lẽ còn hơn thế nữa Tôi khuyên bạn nên tạo một lớp riêng để giữ các biến Bạn cũng có thể làm cho các biến và phương thức tĩnh để tránh phải tạo một đối tượng của lớp Một cách khác là giữ biến cục bộ trong A và chuyển tham chiếu đến B và C trong hàm tạo của chúng. Sau đó, B và C lưu trữ tham chiếu và sử dụng cùng một biến. Điều này gần với một biến toàn cục hơn nhưng nó chỉ được biết giữa 3 lớp. Nó sẽ trông như thế. class A { B * b; C * c; int local }; class B { B(int & loc) : local(loc) { } int & local; }; Và nó sẽ được khởi tạo theo cách đó trong A b = new B(local); Nếu bạn chỉ cần một phiên bản cục bộ, bạn có thể cân nhắc đặt nó ở trạng thái tĩnh. Trong trường hợp đó, bạn sẽ không cần chuyển nó vào hàm tạo Thêm giải pháp của bạn ở đâyB I U S small BIG code class C; class B { C *c; int local1; }; class C { B *b; int local2; };0 < > & link [^] encode untab case indent outdent Xem trước 0thành viên hiện cóhoặc tham gia với chúng tôiTải xuống, Bình chọn, Nhận xét, Xuất bản Email của bạnEmail này đang được sử dụng. Bạn có cần mật khẩu của bạn? Mật khẩu tùy chọnKhi trả lời một câu hỏi xin vui lòng
Nội dung này, cùng với bất kỳ tệp và mã nguồn liên quan nào, được cấp phép theo Giấy phép Mở Dự án Code (CPOL) Chúng tôi cố gắng tránh ban hành các quy tắc và nghị định khi đưa ra lời khuyên về lập trình. Mọi quyết định đều có sự đánh đổi, và đôi khi sự đánh đổi mà người ta cần đưa ra lời khuyên chung hoàn toàn vô hiệu. Tuy nhiên, chúng tôi không thể bỏ qua kinh nghiệm tập thể của toàn bộ ngành công nghiệp của chúng tôi trong nhiều thập kỷ. Điều gì làm cho chúng ta khôn ngoan hơn những người đến trước chúng ta? Một ngọn đồi mà chúng ta sẽ tự hào đứng và chết trên đó là các biến toàn cầu nên tránh trừ khi thực sự cần thiết. Và việc sử dụng chúng hiếm khi thực sự cần thiết. Thay vào đó, chúng tôi thường thấy rằng các nhà phát triển đưa các biến toàn cục và trạng thái toàn cầu vào chương trình của chúng tôi vì lý do thuận tiện, áp lực thời gian hoặc không biết về các khả năng khác Trong mục này, chúng ta sẽ thảo luận về các vấn đề với biến toàn cục, các phương pháp thay thế để chia sẻ dữ liệu, kỹ thuật tái cấu trúc và hướng dẫn khi nào phải sử dụng biến toàn cục Mục lục Các vấn đề với các biến toàn cầuCác biến toàn cục có một số vấn đề Vi phạm che giấu thông tinViệc sử dụng các biến toàn cục cho thấy tính mô đun kém. Nó cũng vi phạm nguyên tắc Ẩn thông tin. Việc triển khai dữ liệu chung có sẵn cho phần còn lại của chương trình – không có cách nào dễ dàng để thay đổi cách dữ liệu được lưu trữ hoặc mã hóa mà không thay đổi từng tham chiếu đến biến đó trong suốt chương trình. Nếu thiết kế lại xảy ra trong tương lai, các thay đổi sẽ diễn ra trong suốt chương trình Phủ nhận nguyên tắc Open-ClosedViệc sử dụng các biến toàn cục phủ nhận khả năng áp dụng Nguyên tắc Đóng Mở (OCP). Bất kỳ thành phần nào phụ thuộc vào một biến toàn cục đều không thể thực sự bị đóng đối với các sửa đổi – một thay đổi trong một thành phần khiến biến được sử dụng theo cách không mong muốn sẽ phá vỡ các thành phần khác sử dụng biến đó Giới thiệu Khớp nối ngầm và Tác dụng phụCác chức năng và mô-đun chia sẻ dữ liệu toàn cầu được liên kết chặt chẽ với nhau. Tuy nhiên, loại khớp nối này rất dễ bị bỏ sót, vì nó không được phản ánh trong thiết kế phần mềm và nó không hiển thị trừ khi phân tích mã nguồn và tìm kiếm tên. Về cơ bản, bạn đang giới thiệu các phụ thuộc ẩn giữa các chức năng và mô-đun Thông thường, các chức năng và mô-đun được kết hợp với dữ liệu chung không có lý do khái niệm nào – dữ liệu có thể dễ dàng được chia sẻ thông qua một cơ chế khác, chẳng hạn như tham số chức năng hoặc gọi lại Khó theo dõiVì hệ thống của anh ta không phản ánh sự đóng gói tốt, nên có thể khó tìm ra chính xác điều gì đang xảy ra trong hệ thống. Ngoài ra, không có kiểm soát truy cập đối với các biến toàn cục, nghĩa là chúng có thể được sửa đổi ở bất cứ đâu – không rõ ai chịu trách nhiệm thay đổi biến Kết quả cuối cùng của những yếu tố này là hậu quả của thay đổi không thể được xác định tại địa điểm thay đổi – thay vào đó, tất cả các cách sử dụng biến phải được phân tích để xác định tác động của thay đổi. Các tác dụng phụ cũng có thể phát sinh từ hai phần khác nhau của chương trình sửa đổi biến theo một trình tự không lường trước được, bởi vì bản chất phân tán của biến gây khó khăn cho việc suy luận chính xác về việc sử dụng nó. Bạn chắc chắn có thể thực hiện phân tích xem mỗi biến toàn cục được viết và đọc ở đâu, nhưng điều này thường tốn thời gian và dễ xảy ra lỗi. Ngoài ra, bí danh (được thảo luận bên dưới) có thể khiến các tìm kiếm đơn giản không chính xác. Mọi thay đổi đối với biến toàn cục sẽ làm mất hiệu lực phân tích này và yêu cầu thực hiện lại Hiệu quả thực tế là các nhà phát triển thực hiện một thay đổi cục bộ trong một khu vực, điều này dẫn đến một lỗi trong một phần khác của mã. Sự phức tạp của hệ thống làm tăng khả năng xảy ra lỗi và khó khăn trong việc theo dõi chúng – biến có thể được đọc và ghi trên toàn hệ thống. Cuối cùng, các nhà phát triển ngừng thực hiện các thay đổi đối với phần mềm vì sợ làm hỏng phần mềm, làm tăng đáng kể hiệu ứng lão hóa. đổ bóngCó thể rơi vào trường hợp bạn bị “biến toàn cục che khuất”, điều này xảy ra khi bạn khai báo một biến cục bộ trùng tên với biến toàn cục. Điều này có thể gây ra hành vi không mong muốn, vì bạn có thể nghĩ rằng mình đang sửa đổi biến toàn cục trong khi thay vào đó, bạn đang làm việc với biến cục bộ. Rất may, trình biên dịch hiện đại có thể tạo cảnh báo cho điều này, nhưng chúng tôi đã làm việc trên các dự án mà cảnh báo này không được bật và bóng mờ xảy ra mà không ai nhận ra, dẫn đến hành vi sai Răng cưaKhông có cách nào để ngăn ai đó tạo bí danh cho biến toàn cục, chẳng hạn như chuyển một con trỏ tới biến toàn cục làm đầu vào hàm. Nếu các biến toàn cục được coi là có hại, thì các con trỏ tới các biến toàn cục hoàn toàn là xấu xa. Điều này gây khó khăn cho việc theo dõi điều gì đang thực sự xảy ra với một biến – bạn có thể tìm kiếm tất cả các trường hợp mà biến toàn cục được ghi vào, hoàn toàn bỏ qua thực tế là có các hàm sửa đổi biến đó thông qua một con trỏ. Điều này khiến cho việc theo dõi các sửa đổi đối với một biến toàn cầu trong chương trình của chúng ta càng khó khăn hơn Điều kiện cuộc đuaTrong các hệ thống đa luồng, các biến toàn cầu đưa ra các điều kiện chủng tộc. Các phương pháp đồng bộ hóa (chẳng hạn như khóa và các phần quan trọng) trở thành một yêu cầu, nhưng chúng thường bị bỏ qua. Khi quyền truy cập biến toàn cục được phân phối trên toàn hệ thống (chứ không phải được chứa trong một mô-đun duy nhất), có thể dễ dàng bảo vệ biến không đúng cách hoặc bỏ lỡ vị trí nơi biến được cập nhật – không có cách nào đảm bảo rằng đồng bộ hóa sẽ được sử dụng ở mọi Sự hiện diện đơn thuần của các biến toàn cục đủ có thể hạn chế một cách hiệu quả chương trình ở dạng đơn luồng do công việc cần thiết để bảo vệ đúng cách đọc/ghi từ mỗi biến Vấn đề đặt hàng khởi tạo toàn cầuTrong C++, thứ tự khởi tạo của biến toàn cục và biến tĩnh tệp là nguồn gây ra sự cố phổ biến trong hệ thống. Tiêu chuẩn nêu rõ rằng các biến toàn cục trong một tệp nguồn duy nhất được tạo và khởi tạo theo thứ tự chúng xuất hiện trong tệp. Tuy nhiên, không có gì đảm bảo cho việc đặt hàng toàn cầu trên các tệp nguồn. Khi toàn cầu trong một tệp tham chiếu toàn cầu trong một tệp khác, thứ tự khởi tạo có thể không như mong đợi, dẫn đến sự cố. Các sự cố này có thể thay đổi tùy thuộc vào cách các tệp đối tượng được liên kết trong bản dựng, dẫn đến các sự cố giả xuất hiện và biến mất theo thời gian Nhận xét Không giúp đỡMột số lập luận rằng những nhược điểm của các biến toàn cục có thể được giảm bớt thông qua nhận xét hợp lý giải thích mục đích và hoạt động của một biến. Tuy nhiên, các loại nhận xét này không giải quyết được sự cố với toàn cầu. Do bản chất của chúng, bạn thậm chí có thể nhận ra rằng những lời giải thích về ý nghĩa của một biến cũng như cách nó được sử dụng và truy cập là hoàn toàn sai. Điều này thường có thể phát sinh do sự phức tạp được đưa ra bằng cách đọc/ghi biến ở nhiều vị trí – ví dụ: các điều kiện cạnh tranh tế nhị có thể tồn tại trong quá trình thực thi do bản chất của mã được tạo, nhưng có thể không được bất kỳ nhà phát triển nào đọc mã chú ý. Nhận xét cũng không giải quyết được vấn đề vì luôn có khả năng thông tin bị lỗi thời do tính chất phân tán của biến khó khăn kiểm traDữ liệu toàn cầu khiến việc kiểm tra trở nên khó khăn. Trong nhiều trường hợp, điều đó có nghĩa là các thành phần riêng lẻ của hệ thống không thể được kiểm tra độc lập. Do khớp nối được giới thiệu bởi các biến toàn cục, toàn bộ hệ thống con hoặc hệ thống phải được kiểm tra Các biến toàn cục cũng gây khó khăn cho việc khôi phục trạng thái của hệ thống đang kiểm thử giữa các trường hợp kiểm thử. Đôi khi, cách duy nhất để thiết lập lại trạng thái rõ ràng là thiết lập lại toàn bộ hệ thống, kéo dài quá trình kiểm tra và làm cho nó dễ hỏng hơn Các lựa chọn thay thế cho các biến toàn cụcNhững người đã quen với việc chia sẻ dữ liệu thông qua các biến toàn cục có thể không biết những công cụ nào khác mà họ có thể tùy ý sử dụng. Bất cứ khi nào bạn muốn tiếp cận dữ liệu toàn cầu, thay vào đó hãy xem xét một trong các tùy chọn sau Giảm phạm viCách hành động đơn giản nhất là giảm phạm vi của biến toàn cục càng nhiều càng tốt. Theo mặc định, bạn nên sử dụng phạm vi thực tế nhỏ nhất cho các biến và hàm
Phân tích theo hướng ngược lại, bạn có thể
Mã có thể được cấu trúc lại để truyền dữ liệu thông qua các tham số chức năng thay vì chia sẻ dữ liệu thông qua các biến toàn cục. Nếu bạn cần sự kiên trì trong một hàm, bạn có thể sử dụng biến tĩnh cục bộ ““ Ghi chú Phạm vi biến toàn cầu thường có thể được giảm bớt bằng cách xem xét lại cách bạn tổ chức mã nguồn của mình. Xem phần để biết thêm thông tin Truy cập dữ liệu thông qua giao diệnLý tưởng nhất là dữ liệu toàn cầu không nên được ghi hoặc đọc trực tiếp từ. Thay vào đó, bạn có thể di chuyển dữ liệu vào một mô-đun và chỉ cung cấp dữ liệu đó thông qua API. Ngoài việc giảm phạm vi, điều này đảm bảo rằng người dùng dữ liệu chỉ có thể thực hiện các hoạt động dự định trên biến. Điều này giúp loại bỏ khả năng đặt một giá trị tùy ý sai có tác động tiêu cực đến chương trình. Một lợi ích khác đối với kiểm soát cục bộ là việc đảm bảo rằng biến được bảo vệ đúng cách trong các tình huống đa luồng trở nên dễ dàng hơn nhiều ““ Ghi chú Xem phần để biết thêm thông tin Thông quaThông thường, phần mềm hệ thống nhúng sử dụng các biến toàn cục để chia sẻ thông tin giữa các ngữ cảnh, chẳng hạn như đọc dữ liệu trong ISR và cung cấp dữ liệu đó trong vòng lặp chính hoặc truyền dữ liệu giữa nhiều luồng. Thay vì sử dụng các biến toàn cục, có thể sử dụng một hàng đợi (e. g. , để truyền tin nhắn, sự kiện hoặc giá trị dữ liệu mới). Những hàng đợi như vậy thường được cung cấp nhiều RTOS, nhưng chúng cũng có thể được tạo từ bộ đệm vòng. Phạm vi của hàng đợi có thể được giảm xuống để nó chỉ khả dụng cho (những) người sản xuất và người tiêu dùng cần thiết, cho dù đó là thông qua một biến tĩnh của tệp hay được cung cấp bằng cách chuyển tay cầm hàng đợi vào một mô-đun dưới dạng tham số chức năng ““ đọc thêm Để biết thêm về chủ đề này, hãy xem mục Truyền tin nhắn gọi lạiMột cách khác để chia sẻ giá trị dữ liệu mới với các khách hàng quan tâm là thông qua việc sử dụng các lệnh gọi lại (hay nói chung hơn là mẫu Người quan sát). Bất cứ khi nào có dữ liệu mới, nhà sản xuất có thể chia sẻ dữ liệu đó bằng cách gọi tất cả các cuộc gọi lại đã đăng ký và chuyển dữ liệu mới theo tham số Kỹ thuật tái cấu trúcNếu bạn đang cố gắng gỡ rối một thiết kế phụ thuộc nhiều vào dữ liệu toàn cầu, bạn có thể sử dụng các kỹ thuật sau
Quy tắc khi Globals phải được sử dụngLý tưởng nhất là không có biến nào trong một hệ thống sẽ là toàn cầu (ngoại trừ các biến toàn cầu đặc biệt như hằng số toán học và thông tin cấu hình thời gian biên dịch). Tuy nhiên, nếu các biến toàn cục được sử dụng, chúng tôi đề xuất các quy tắc sau
Khi dữ liệu chung được sử dụng cho một giá trị cấu hình, hằng số toán học hoặc giá trị khác không thay đổi trong thời gian chạy, hãy đảm bảo
Người giới thiệu
|