2013-04-29 36 views
6

Nếu tôi làm như sau tất cả là ok:trống static_cast * char * vs static_cast trống ** char **

char* cp = "abc"; 
void* vp = NULL; 
vp = static_cast<void*>(cp);//ok 
cp = static_cast<char*>(vp);//ok 

Nhưng đây không phải là:

char** cpp = &cp; 
void** vpp = NULL; 
vpp = static_cast<void**>(cpp);//error C2440: 'static_cast': 
           //cannot convert from 'char **' to 'void **' 
cpp = static_cast<char**>(vpp);//error C2440: 'static_cast': 
           //cannot convert from 'void **' to 'char **' 

Hãy thể ai đó giải thích cho tôi tại sao các ví dụ thứ hai không được phép. Xin vui lòng không trích dẫn tiêu chuẩn C++ như câu trả lời của bạn, bởi vì tôi đã nhìn thấy câu trả lời trích dẫn nó, và tôi không hiểu ý nghĩa của chúng. Tôi muốn hiểu lý do tại sao ví dụ thứ hai không hoạt động (ví dụ: nếu bạn có thể đưa ra một ví dụ về việc sẽ rất nguy hiểm khi đó sẽ là một trợ giúp lớn). Bởi vì tôi không hiểu. Với tôi, cả hai ví dụ đều là con trỏ. Tại sao một mức độ khác biệt của indirection tạo ra bất kỳ sự khác biệt nào?

+6

Bạn có thể chuyển đổi hoàn toàn bất kỳ con trỏ nào thành 'void *' và tĩnh đúc theo hướng ngược lại. Nhưng điều này không đúng với 'T *' và 'U *' nói chung, điều này không liên quan. (Bây giờ hãy suy nghĩ 'T = char *' và 'U = void *'.) –

+0

Bạn có thể tạo một 'char **' thành 'void *' và ngược lại. –

+1

@Kerrek SB - Có, nhưng tại sao điều này lại không được phép? Khi nào điều này sẽ không an toàn? – e244

Trả lời

12

A void * con trỏ có thể trỏ đến "mọi thứ" và hợp lệ để chuyển đổi tất cả các con trỏ thành void * và nó hợp lệ để chuyển đổi tất cả các con trỏ từ void * sang một số loại khác.

Tuy nhiên, void ** là con trỏ trỏ đến giá trị void *. Và char ** là con trỏ trỏ tới giá trị char *. Các loại này không trỏ đến các loại có thể chuyển đổi được với nhau. Bạn có thể, nếu bạn CẦN làm điều này, hãy sử dụng void **vpp = reinterpret_cast<void **>(cpp);, nhưng nó "không an toàn" (về cơ bản bạn đang nói với trình biên dịch "Hãy nhìn xem, tôi biết những gì tôi đang làm ở đây, vì vậy chỉ cần làm điều đó", có thể không làm những gì bạn thực sự mong đợi ...)

+0

+1 cho ghi chú về "không an toàn" –

+0

Tôi xin lỗi, tôi vẫn không hiểu. Nếu một số chuỗi có địa chỉ 0x12345678, tôi có thể đặt trong char * của tôi hoặc void của tôi *. Nếu địa chỉ của char * của tôi là 0x87654321, tại sao tôi không thể đặt giá trị đó (địa chỉ 0x87654321) trong khoảng trống ** của tôi? I E.tại sao nó ok để static_cast 0x12345678 đến một void *, nhưng không ok để static_cast 0x87654321 đến một void **? Khi nào/tại sao điều này sẽ không an toàn? – e244

+0

@ e244: Vấn đề là bạn có thể dễ dàng (và không có bất kỳ diễn viên rõ ràng nào) phá hoại hệ thống kiểu nếu chuyển đổi đó được cho phép. Tôi đã cung cấp một giải thích dài hơn như một câu trả lời, nhưng mô tả ngắn gọn sẽ là con trỏ kép cho phép bạn thay đổi dữ liệu theo những cách không an toàn. –

6

Hạn chế là tránh phá vỡ hệ thống kiểu. Chuyển đổi đầu tiên là tốt:

type *p = ...; 
void *vp = p; 

Trong khi bạn đang cho đi các loại, bạn có thể không gây quá nhiều thiệt hại cho các giá trị ban đầu mà không cần vì có rất ít được thực hiện với một đối tượng void và tất cả những thay đổi để vp là cục bộ cho con trỏ và không thể ảnh hưởng đến p.

Nếu trường hợp thứ hai được phép:

type **p = ...; 
void **vp = p; 

Sau đó một cách hoàn hảo tìm kiếm và mã đúng có thể phá vỡ ứng dụng của bạn. Ví dụ:

int *parray[10]; 
int **p = parray; 
void **vp = p; 
*vp = new double(); // now parray[0] is a pointer to a double object, 
        // not a pointer to an int!!! 

Hệ thống kiểu đã bị hủy.

Đó là, vấn đề là trong trường hợp thứ hai có các hoạt động có thể được áp dụng cho con trỏ đích có thể sửa đổi đối tượng ban đầu và gây ra lỗi. Ví dụ tương tự có thể được tìm thấy với const trường hợp khác (bạn có thể chuyển đổi int* thành const int*, nhưng bạn không thể chuyển đổi int** thành const int** ...).

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