2010-02-27 30 views
12

Tôi đã đọc rất nhiều về việc đúc C++ và tôi bắt đầu bị lẫn lộn vì tôi luôn sử dụng tính năng đúc kiểu C.Bối rối trên C++ đúc

Tôi đã đọc rằng việc truyền kiểu C nên tránh trong C++ và reinterpret_cast rất nguy hiểm và không nên sử dụng bất cứ khi nào có thay thế. Ngược lại với việc không sử dụng reinterpret_cast, tôi đã thấy nó được sử dụng nhiều lần trên MSDN trong mã mẫu của họ. Điều này dẫn tôi đến câu hỏi đầu tiên của tôi, khi nào thì ok để sử dụng reinterpret_cast?

Ví dụ:

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch (Msg) 
    { 
     case WM_CREATE: 
     { 
      LPCREATESTRUCT lpCreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); 
      return 0; 
     } 
    } 

    ... 
} 

Nếu đó không phải là ok, sau đó thế nào tôi sẽ đúc giá trị LPARAM đến một con trỏ chỉ sử dụng tĩnh, năng động, và/hoặc const đúc?

Ngoài ra: Nếu reinterpret_cast là không di động, thế nào tôi sẽ viết lại nó để được cầm tay (đối với thực hành tốt)

+1

Đây có thể là cơ sở mã cũ. –

Trả lời

8

Sử dụng reinterpret_cast là chấp nhận được nếu bạn biết rằng con trỏ ban đầu của các loại đích. Bất kỳ việc sử dụng nào khác đang lợi dụng hành vi phụ thuộc vào thực thi, mặc dù trong nhiều trường hợp, điều này là cần thiết và hữu ích, chẳng hạn như đúc một con trỏ tới một cấu trúc thành một con trỏ tới các byte để nó có thể được tuần tự hóa.

Nó được coi là nguy hiểm vì nó không kiểm tra, hoặc tại thời gian biên dịch hoặc khi chạy. Nếu bạn phạm sai lầm, nó có thể và sẽ sụp đổ và đốt cháy khủng khiếp, và khó khăn để gỡ lỗi. Về cơ bản, bạn nói với trình biên dịch "Tôi biết rõ hơn bạn thực sự là cái gì, vì vậy chỉ cần biên dịch mã và để tôi lo lắng về hậu quả."

+1

Nối tiếp cấu trúc theo cách đó là một ý tưởng tồi (ngay cả khi thường được thực hiện), nhưng đó là một chủ đề cho một câu hỏi khác. – Tronic

5

Lý do bạn thấy nó trên MSDN là vì API Win32 là một API C, nhưng mọi người nhấn mạnh vào việc đưa ra các ví dụ trong C++.

Việc diễn giải lại diễn giải là tốt khi bạn viết mã giao diện với các thư viện khác. Bạn nên tránh trong ứng dụng của riêng mình.

2

Không để thiếu tôn trọng MSDN, nhưng MSDN không phải là nơi tốt nhất để đi cho mã hóa C++ phù hợp.

Một lý do để sử dụng reinterpret_cast là khi bạn truyền đến/từ kiểu dữ liệu mờ. reinterpret_cast không phải là "nguy hiểm" nó chỉ là nó dễ dàng để vít lên và dẫn đến các vấn đề trong mã của bạn, đó là lý do tại sao nó nên tránh.

Lý do tại sao phôi kiểu C++ được ưu tiên hơn, static_cast là an toàn và mọi lần truyền đều dễ tìm kiếm hơn.

Người lập trình [không chính xác] thường sử dụng phôi để "loại bỏ cảnh báo trình biên dịch" chẳng hạn như chuyển đổi từ số chưa ký sang số nguyên đã ký hoặc từ số nguyên 32 bit sang số nguyên 8 bit.

+1

+1. MSDN là chock đầy MS-isms. Những cuốn sách hay của Scott Meyers và Herb Sutter (mặc dù bây giờ anh đang ở MS, anh ấy là một nhà văn xuất sắc và có nhiều lời khuyên tuyệt vời về viết tốt C++) là những nơi tốt hơn để củng cố sự hiểu biết của họ về thực hành C++ tốt. –

+0

@Matt Curtis - Tôi thấy phần khó chịu hơn về MSDN là MS-isms được áp dụng không nhất quán. Chất lượng thay đổi rất nhiều với các ví dụ của họ. Nói chung, tuy nhiên, bạn không nên sao chép các ví dụ của họ; nó có thể cung cấp cho bạn một ý tưởng thô, nhưng bạn nên thích nghi những ý tưởng đó với bất kỳ kiểu mã hóa nào được sử dụng trong dự án mà bạn đang làm việc. – asveikau

2

Về cơ bản reinterpret_cast là "an toàn" với cấu trúc C và các loại cơ bản (chặn các lỗi đồng bằng như đúc int tới con trỏ và quay lại, hoạt động trên kiến ​​trúc ILP32 nhưng bị hỏng trên LP64.) Cấu trúc AC không có gì trong đó , ngoại trừ phần đệm có thể cho căn chỉnh, mà bạn không khai báo.

reinterpret_cast là không an toàn với các loại đa hình C++ từ trình biên dịch chèn mục dữ liệu vào lớp học của bạn - những thứ như con trỏ đến bảng ảocon trỏ tới lớp cơ sở ảo. C++ khác phôi chăm sóc điều chỉnh những khi, nói, xuống đúc từ con trỏ đến lớp cơ sở để con trỏ đến lớp dẫn xuất, reinterpret_cast và phôi kiểu C không.

3

Đây là ví dụ về lập trình SDK nền tảng Windows, API C, với C++. Thủ tục cửa sổ chỉ có các tham số WPARAM và LPARAM và nếu bạn cần truyền một con trỏ tới một cấu trúc thông qua một thông báo cửa sổ, nó phải được đúc. Đây là cách sử dụng hoàn toàn có thể chấp nhận được của reinterpret_cast <> theo ý kiến ​​của tôi. Bạn không thể tránh một diễn viên vì SDK bạn đang viết, không phải là mã của bạn, không được thiết kế cho C++, ít an toàn hơn nhiều, và cần truyền để cung cấp các kiểu tham số chung với một ràng buộc C.

reinterpret_cast <> đây là một lá cờ cho bạn biết bạn cần phải cẩn thận, nhưng nó không phải là tránh được bằng mọi giá.

Nếu, mặt khác, bạn kiểm soát cả hai mặt của mã, API và người tiêu dùng, sẽ tốt hơn nếu tạo một API an toàn và không yêu cầu người tiêu dùng thực hiện phôi để sử dụng nó đúng.

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