Có an toàn để kiểm tra một con trỏ không NULL
bằng cách viết đơn giản if(pointer)
hoặc tôi phải sử dụng if(pointer != NULL)
?
NULL
trong C ++ từ đây vì NULL
macro phụ thuộc triển khai có thể mang lại cho bạn những hành vi mơ hồ.
Có an toàn để kiểm tra một con trỏ không NULL
bằng cách viết đơn giản if(pointer)
hoặc tôi phải sử dụng if(pointer != NULL)
?
NULL
trong C ++ từ đây vì NULL
macro phụ thuộc triển khai có thể mang lại cho bạn những hành vi mơ hồ.
Câu trả lời:
Bạn có thể; con trỏ null được ngầm định chuyển thành boolean false trong khi con trỏ không null được chuyển đổi thành true. Từ tiêu chuẩn C ++ 11, phần về Chuyển đổi Boolean:
Một giá trị của số học, liệt kê không được điều chỉnh, con trỏ hoặc con trỏ thành loại thành viên có thể được chuyển đổi thành một giá trị của loại
bool
. Giá trị 0, giá trị con trỏ null hoặc giá trị con trỏ null được chuyển đổi thànhfalse
; bất kỳ giá trị nào khác được chuyển đổi thànhtrue
. Một giá trị của loạistd::nullptr_t
có thể được chuyển đổi thành một giá trị của loạibool
; giá trị kết quả làfalse
.
Đúng bạn có thể.
Đây là một phần của chuyển đổi tiêu chuẩn C ++, nằm trong mệnh đề chuyển đổi Boolean :
§ 4.12 Chuyển đổi Boolean
Một giá trị của số học, liệt kê không được điều chỉnh, con trỏ hoặc con trỏ thành loại thành viên có thể được chuyển đổi thành một giá trị của loại bool. Giá trị 0, giá trị con trỏ null hoặc giá trị con trỏ null được chuyển thành false; bất kỳ giá trị nào khác được chuyển đổi thành true. Một giá trị của loại std :: nullptr_t có thể được chuyển đổi thành một giá trị của loại bool; giá trị kết quả là sai.
Vâng, bạn có thể. Trong thực tế, tôi thích sử dụngif(pointer)
vì đọc và viết đơn giản hơn một khi bạn đã quen với nó.
Cũng lưu ý rằng C ++ 11 được giới thiệu nullptr
được ưa thích hơn NULL
.
if(som_integer)
vs if(some_integer != 0)
vì số nguyên cũng không phải là booleans, phải không? Tôi muốn tránh 0
hoặc NULL
trong một tuyên bố if.
if (pointer)
bản thân mình, nhưng if (ptr != nullptr)
dường như hoàn toàn hợp pháp với tôi. Mặt khác, nếu tôi thấy ai đó trong nhóm của mình viết if (some_integer)
tôi sẽ khiến họ đổi nó thành if (some_integer != 0)
. Tuy nhiên, tôi sẽ không giả vờ rằng đó không phải là một sở thích tương đối độc đoán về phía tôi - tôi chỉ đơn giản là không thích đối xử với con trỏ và số nguyên như nhau.
if(isReady)
if(filePtr)
if(serviceNo)
? Đặt tên biến xấu về mục đích không có ý nghĩa nhiều trong trường hợp này. Dù sao tôi cũng đã có quan điểm của bạn và hiểu nó, nhưng tôi có thể khăng khăng sử dụng phong cách mã hóa của riêng mình, OK?
Câu hỏi được trả lời, nhưng tôi muốn thêm điểm của tôi.
Tôi sẽ luôn luôn thích if(pointer)
thay vì if(pointer != NULL)
và if(!pointer)
thay vì if(pointer == NULL)
:
Ít cơ hội để viết mã lỗi, giả sử nếu tôi viết sai chính tả toán tử kiểm tra ==
bằng =
if(pointer == NULL)
có thể bị sai chính tả if(pointer = NULL)
Vì vậy tôi sẽ tránh nó, tốt nhất là chỉ if(pointer)
.
(Tôi cũng đề xuất một số điều kiện Yoda trong một câu trả lời , nhưng đó là vấn đề khác nhau)
Tương tự như vậy while (node != NULL && node->data == key)
, tôi sẽ chỉ đơn giản viết while (node && node->data == key)
điều đó rõ ràng hơn với tôi (cho thấy rằng sử dụng ngắn mạch).
(boolean expression)? true : false
là hoàn toàn vô nghĩa. Biểu thức đánh giá hoặc true
hoặc false
; những gì bạn nói là "nếu nó đúng, hãy cho tôi đúng, nếu nó sai, hãy cho tôi sai". Tóm lại: Nó hoàn toàn tương đương với chính biểu thức boolean. Lưu ý rằng đó node == NULL
là một biểu thức boolean. BTW, hai triển khai của bạn trả lại chính xác đối lập với nhau. Hoặc bạn muốn !=
trong lần đầu tiên, hoặc chỉ một !
trong lần thứ hai.
=
thay vì ==
là tạo các biến của bạn const
bất cứ khi nào có thể. Ví dụ, bạn có thể định nghĩa hàm của mình là isEmnpy(node* const head) { ... }
, và sau đó trình biên dịch sẽ từ chối biên dịch nó nếu bạn vô tình viết node = NULL
thay vì node == NULL
. Tất nhiên, nó chỉ hoạt động cho các biến mà bạn thực sự không cần phải thay đổi.
T* get() const
thay vì operator T*() const
để tránh chuyển đổi ngầm. Họ tuy nhiên có một operator bool() const
.
Vâng, bạn có thể. Khả năng so sánh các giá trị với các số không hoàn toàn đã được kế thừa từ C và có trong tất cả các phiên bản của C ++. Bạn cũng có thể sử dụng if (!pointer)
để kiểm tra con trỏ cho NULL.
Các trường hợp sử dụng có liên quan cho con trỏ null là
Phôi động. Việc truyền một con trỏ lớp cơ sở sang một lớp dẫn xuất cụ thể (một điều bạn nên cố gắng tránh một lần nữa, nhưng đôi khi có thể thấy cần thiết) luôn thành công, nhưng dẫn đến một con trỏ null nếu lớp dẫn xuất không khớp. Một cách để kiểm tra điều này là
Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
if(derived_ptr != nullptr) { ... }
(hoặc, tốt nhất là, auto derived_ptr = ...
). Bây giờ, điều này là xấu, bởi vì nó để con trỏ dẫn xuất (có thể không hợp lệ, tức là null) bên ngoài if
phạm vi của khối bảo vệ an toàn . Điều này là không cần thiết, vì C ++ cho phép bạn giới thiệu các biến có thể chuyển đổi boolean bên trong một if
-condition :
if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr)) { ... }
không chỉ ngắn hơn và an toàn phạm vi, nó còn rõ ràng hơn nhiều trong ý định của nó: khi bạn kiểm tra null trong một điều kiện if riêng biệt, người đọc tự hỏi "ok, vậy thì derived_ptr
không phải là null ở đây ... tốt, tại sao nó là null? " Trong khi đó, phiên bản một dòng nói rất rõ ràng "nếu bạn có thể yên tâm đúc base_ptr
đểDerived*
, sau đó sử dụng nó cho ...".
Điều tương tự cũng hoạt động tương tự đối với bất kỳ hoạt động thất bại có thể nào khác trả về một con trỏ, mặc dù IMO bạn thường nên tránh điều này: tốt hơn là sử dụng một cái gì đó như boost::optional
là "thùng chứa" cho kết quả của các hoạt động có thể thất bại, thay vì con trỏ.
Vì vậy, nếu các trường hợp sử dụng chính cho con trỏ null luôn cần được viết bằng một biến thể của implicit-cast-phong cách, tôi muốn nói đó là tốt vì những lý do nhất quán để luôn sử dụng phong cách này, tức là tôi muốn biện hộ cho if(ptr)
qua if(ptr!=nullptr)
.
Tôi e rằng tôi phải kết thúc bằng một quảng cáo: if(auto bla = ...)
cú pháp thực sự chỉ là một xấp xỉ hơi cồng kềnh đối với giải pháp thực sự cho các vấn đề như vậy: khớp mẫu . Tại sao trước tiên bạn sẽ buộc một số hành động (như đúc một con trỏ) và sau đó xem xét rằng có thể có một thất bại ... Ý tôi là, thật nực cười, phải không? Giống như, bạn có một số thực phẩm và muốn nấu súp. Bạn đưa nó cho trợ lý của bạn với nhiệm vụ trích xuất nước ép, nếu đó là một loại rau mềm. Trước tiên bạn không nhìn vào nó. Khi bạn có một củ khoai tây, bạn vẫn đưa nó cho trợ lý của mình nhưng họ lại tát nó vào mặt bạn với một ghi chú thất bại. Ah, lập trình bắt buộc!
Tốt hơn nhiều: xem xét ngay lập tức tất cả các trường hợp bạn có thể gặp phải. Sau đó hành động phù hợp. Haskell:
makeSoupOf :: Foodstuff -> Liquid
makeSoupOf p@(Potato{..}) = mash (boil p) <> water
makeSoupOf vegetable
| isSoft vegetable = squeeze vegetable <> salt
makeSoupOf stuff = boil (throwIn (water<>salt) stuff)
Haskell cũng có các công cụ đặc biệt khi thực sự có khả năng thất bại nghiêm trọng (cũng như cho cả đống thứ khác): monads. Nhưng đây không phải là nơi để giải thích những điều đó.
⟨/Quảng cáo⟩
if(ptr)
chứ không phải if(ptr != nullptr)
, có nhiều điều để nói hơn.
Phải, tất nhiên! trong thực tế, viết if (con trỏ) là cách viết thuận tiện hơn thay vì if (con trỏ! = NULL) vì: 1. rất dễ gỡ lỗi 2. dễ hiểu 3. nếu vô tình, giá trị của NULL được xác định, sau đó mã sẽ không bị sập
Đúng. Trong thực tế bạn nên. Nếu bạn đang tự hỏi nếu nó tạo ra một lỗi phân khúc , thì không.
Như những người khác đã trả lời tốt, cả hai đều có thể thay thế cho nhau.
Tuy nhiên, điều đáng nói là có thể có trường hợp bạn muốn sử dụng câu lệnh rõ ràng, nghĩa là pointer != NULL
.
Có, bạn luôn có thể làm điều này khi điều kiện 'IF' chỉ đánh giá khi điều kiện bên trong nó trở thành sự thật. C không có kiểu trả về boolean và do đó trả về giá trị khác không khi điều kiện là đúng trong khi trả về 0 bất cứ khi nào điều kiện trong 'IF' hóa ra là sai. Giá trị khác không được trả về theo mặc định là 1. Do đó, cả hai cách viết mã đều đúng trong khi tôi sẽ luôn thích cách thứ hai.
Tôi nghĩ như một quy tắc tự nhiên, nếu biểu thức if của bạn có thể được viết lại thành
const bool local_predicate = *if-expression*;
if (local_predicate) ...
sao cho nó không gây ra CẢNH BÁO, thì THAT phải là kiểu ưa thích cho biểu thức if . (Tôi biết rằng tôi nhận được cảnh báo khi tôi gán C BOOL
( #define BOOL int
) cũ cho C ++ bool
, chứ đừng nói đến con trỏ.)
"Nó có an toàn không..?" là một câu hỏi về tiêu chuẩn ngôn ngữ và mã được tạo.
"Là một thực hành tốt?" là một câu hỏi về mức độ hiểu biết của tuyên bố bởi bất kỳ người đọc tùy ý của con người về tuyên bố. Nếu bạn đang hỏi câu hỏi này, nó gợi ý rằng phiên bản "an toàn" ít rõ ràng hơn đối với các độc giả và nhà văn trong tương lai.
0
hoặcnullptr
. (NULL
là một C'ism, và yêu cầu bao gồm một tệp tiêu đề.)