2009-03-23 43 views
46

Tôi mới dùng phôi kiểu C++ và tôi lo lắng rằng việc sử dụng phôi kiểu C++ sẽ làm hỏng hiệu suất ứng dụng của tôi vì tôi có real-time-critical deadline trong gián đoạn dịch vụ-thường xuyên của tôi.Hiệu suất đạt được từ các phôi kiểu C++?

Tôi nghe nói rằng một số phôi thậm chí sẽ ném ngoại lệ!

Tôi muốn sử dụng phôi kiểu C++ vì nó sẽ làm cho mã của tôi thêm "mạnh mẽ". Tuy nhiên, nếu có bất kỳ hiệu suất nào đạt được thì có thể tôi sẽ không sử dụng phôi kiểu C++ và thay vào đó sẽ dành nhiều thời gian kiểm tra mã sử dụng phôi kiểu C.


Có ai thực hiện bất kỳ kiểm tra/định dạng nghiêm ngặt nào để so sánh hiệu suất của phôi kiểu C++ với phôi kiểu C không?

Kết quả của bạn là gì?

Bạn đã rút ra kết luận gì?

+0

Tôi có thể phải thêm tiền thưởng vào tài khoản này ... đó là cách tôi quan tâm. –

+0

Bạn đã có hai câu trả lời chính xác (nếu tôi nói như vậy). –

+0

Các câu trả lời hiện tại ở đây chỉ ra rằng kiểu C++ static_cast không có hiệu suất thời gian chạy. Có ai đó xin vui lòng bình luận hoặc thêm một số lời giải thích là tại sao họ sẽ có cùng một hiệu suất? (Câu hỏi có mục đích mơ hồ.) –

Trả lời

77

Nếu kiểu đúc kiểu C++ có thể được thay thế bằng một kiểu đúc kiểu C, sẽ không có phí. Nếu không thể, như trong trường hợp của dynamic_cast, mà không có tương đương C, bạn phải trả chi phí theo cách này hay cách khác.

Như một ví dụ, đoạn mã sau:

int x; 
float f = 123.456; 

x = (int) f; 
x = static_cast<int>(f); 

tạo ra mã giống hệt nhau cho cả hai phôi với VC++ - mã là:

00401041 fld   dword ptr [ebp-8] 
00401044 call  __ftol (0040110c) 
00401049 mov   dword ptr [ebp-4],eax 

Các chỉ C++ dàn diễn viên mà có thể ném là dynamic_cast khi đúc để một tài liệu tham khảo. Để tránh điều này, hãy truyền tới một con trỏ, sẽ trả về 0 nếu quá trình truyền không thành công.

+3

Một diễn viên kiểu C++ không bao giờ được thay thế bởi một dàn diễn viên kiểu C. Nếu bất cứ điều gì, đó là cách khác xung quanh. Tiêu chuẩn chỉ xác định hành vi của các phôi kiểu C++. Các kiểu C được mô tả dưới dạng C++. – jalf

+1

@ jalf yes - Tôi có nghĩa là thay thế conceptualy –

+0

Vâng, nhưng có thể có giá trị làm cho nó 110% rõ ràng, nếu OP sẽ chấp nhận nó. ;) – jalf

39

Người duy nhất có bất kỳ chi phí bổ sung nào khi chạy là dynamic_cast, có khả năng không thể sao chép trực tiếp bằng dàn diễn viên kiểu C. Vì vậy, bạn không có vấn đề gì.

Cách dễ nhất để trấn an bản thân về điều này là hướng dẫn trình biên dịch của bạn tạo ra đầu ra của bộ lắp ráp và kiểm tra mã mà nó tạo ra. Ví dụ, trong bất kỳ trình biên dịch được thực hiện một cách an toàn, reinterpret_cast sẽ biến mất hoàn toàn, bởi vì nó chỉ có nghĩa là "đi mù quáng trước và giả vờ dữ liệu thuộc kiểu này".

4

Khi sử dụng dynamic_cast một số kiểm tra được thực hiện trong thời gian chạy để ngăn cản bạn làm điều gì đó ngu ngốc (thêm tại GCC mailing list), chi phí của một dynamic_cast phụ thuộc vào có bao nhiêu lớp học bị ảnh hưởng, những gì các lớp học bị ảnh hưởng vv
Nếu bạn thực sự chắc chắn dàn diễn viên là an toàn, bạn vẫn có thể sử dụng reinterpret_cast.

+0

Nếu bạn thấy bạn cần sử dụng reinterpret_cast, bạn chắc chắn mạo hiểm vào lãnh thổ "thực hiện cụ thể" và có thể là "hành vi không xác định" đất quá –

+0

Xin lưu ý rằng reinterpret_cast có thể tuân theo các quy tắc bí danh khác với static_cast v.v. – leander

16

Tại sao có hiệu suất truy cập? Chúng thực hiện chính xác cùng chức năng như C phôi. Điểm khác biệt duy nhất là chúng thu được nhiều lỗi hơn vào thời gian biên dịch và chúng dễ tìm kiếm hơn trong mã nguồn của bạn.

static_cast<float>(3) chính xác tương đương với (float)3 và sẽ tạo chính xác cùng một mã.

Cho một số float f = 42.0f reinterpret_cast<int*>(&f) tương đương chính xác với (int*)&f và sẽ tạo chính xác cùng một mã.

Và cứ tiếp tục như vậy. Dàn diễn viên duy nhất khác biệt là dynamic_cast, mà, vâng, có thể ném một ngoại lệ. Nhưng đó là bởi vì nó làm những việc mà dàn diễn viên kiểu C không thể làm được. Vì vậy, không sử dụng dynamic_cast trừ khi bạn cần chức năng của nó.

Nó thường là an toàn để giả định rằng các nhà văn biên dịch là thông minh. Với hai biểu thức khác nhau có cùng ngữ nghĩa theo tiêu chuẩn, thường là an toàn để giả định rằng chúng sẽ được thực hiện giống hệt nhau trong trình biên dịch.

Rất tiếc: Ví dụ thứ hai nên được reinterpret_cast chứ không phải dynamic_cast, tất nhiên. Sửa lỗi ngay bây giờ.

Ok, chỉ để làm cho nó hoàn toàn rõ ràng, đây là những gì chuẩn C++ nói:

§5.4.5:

Quá trình chuyển đổi được thực hiện bởi

  • một const_cast (5.2 .11)
  • a static_cast (5.2.9)
  • a.210 theo sau là một const_cast
  • một reinterpret_cast (5.2.10), hoặc
  • một reinterpret_cast theo sau là một const_cast.

có thể được thực hiện bằng cách sử dụng ký hiệu ký hiệu chuyển đổi loại rõ ràng. Các hạn chế giống nhau về ngữ nghĩa và áp dụng các hành vi . Nếu chuyển đổi có thể được giải thích ở nhiều hơn một trong số cách được liệt kê ở trên, thì cách diễn giải xuất hiện đầu tiên trong danh sách là được sử dụng, ngay cả khi dàn diễn viên kết quả là .

Vì vậy, nếu bất cứ điều gì , kể từ khi các diễn viên C-phong cách được thực hiện trong điều khoản của C++ phôi, phôi C-style nên chậm. (Tất nhiên là không, bởi vì trình biên dịch tạo ra cùng một mã trong mọi trường hợp, nhưng nó hợp lý hơn so với các kiểu dáng C++-style đang chậm hơn.)

+0

Đưa ra nhận xét của bạn về : "thường là an toàn để giả định rằng chúng sẽ được thực hiện giống hệt trong trình biên dịch". Bạn hoặc bạn đã thực hiện bất kỳ công việc được nhúng nào hay công việc quan trọng trong thời gian thực? –

+0

dynamic_cast sẽ chỉ ném khi hoạt động trên tham chiếu. Nếu nó đang làm việc trên một con trỏ, nó sẽ trả về 0 nếu cast không thành công. Và tại sao trên trái đất bạn sẽ sử dụng dynamic_cast trên một float * để int * chuyển đổi? Điều đó không có ý nghĩa gì cả. –

+0

oh oops, tôi có nghĩa là reinterpret_cast, tất nhiên. Bây giờ nó đã được sửa. Cảm ơn đã chỉ ra điều đó. :) – jalf

3

Mặc dù tôi đồng ý với tuyên bố "chỉ có một chi phí khi chạy là dynamic_cast ", hãy nhớ rằng có thể có sự khác biệt về trình biên dịch cụ thể.

Tôi đã nhìn thấy một vài lỗi được gửi đối với trình biên dịch hiện tại của tôi, nơi tạo mã hoặc tối ưu hóa hơi khác nhau tùy thuộc vào việc bạn sử dụng kiểu C-style so với C++ - kiểu static_cast.

Vì vậy, nếu bạn lo lắng, hãy kiểm tra việc tháo gỡ trên các điểm phát sóng. Nếu không, chỉ cần tránh các phôi động khi bạn không cần chúng. (Nếu bạn tắt RTTI, bạn không thể sử dụng dynamic_cast.)

+0

Tôi muốn được xem một ví dụ về việc sử dụng dynamic_cast khi bạn không cần nó. –

+1

Một ví dụ có thể là nếu bạn downcast đến một lớp dẫn xuất (vì vậy bạn thường sử dụng dynamic_cast), nhưng bạn đã biết rằng diễn viên là hợp pháp, vì vậy bạn có thể sử dụng static_cast thay thế. – jalf

+1

@Neil: Tôi đoán tôi có ý nghĩa hơn dọc theo dòng "refactor to avoid dynamic_cast". Tôi trông khá khó khăn trước những hậu quả trước khi tôi bắt đầu gắn bó "ảo" trong hệ thống phân cấp thừa kế, bởi vì tôi biết * Tôi đang cân bằng, và đôi khi chọn một mẫu thiết kế khác có thể giải quyết vấn đề ... – leander

15

Có bốn C++ phong cách phôi:

  • const_cast
  • static_cast
  • reinterpret_cast
  • dynamic_cast

Như đã đề cập, ba đầu tiên là hoạt động thời gian biên dịch. Không có hình phạt thời gian chạy cho việc sử dụng chúng. Họ là những thông điệp cho trình biên dịch rằng dữ liệu đã được khai báo một cách cần phải được truy cập theo một cách khác. "Tôi đã nói đây là số int*, nhưng hãy để tôi truy cập nó như thể nó là char* trỏ tới sizeof(int) char s" hoặc "Tôi đã nói dữ liệu này là chỉ đọc và bây giờ tôi cần chuyển nó đến một hàm không sửa đổi nhưng không lấy tham số làm tham chiếu const. "

Bên cạnh tham nhũng dữ liệu bằng cách đúc các loại sai và trouncing trên dữ liệu (luôn luôn là một khả năng với C-style phôi) vấn đề thời gian chạy phổ biến nhất với các diễn viên là dữ liệu mà thực sự được khai báo const không có thể cast được để không const. Truyền một cái gì đó tuyên bố const để không const và sau đó sửa đổi nó là không xác định. Undefined means you're not even guaranteed to get a crash.

dynamic_cast là cấu trúc thời gian chạy và phải có chi phí thời gian chạy.

Giá trị của các phôi này là chúng đặc biệt nói những gì bạn đang cố gắng truyền từ/đến, dính trực quan và có thể tìm kiếm bằng các công cụ chết não. Tôi khuyên bạn nên sử dụng chúng hơn bằng cách sử dụng phôi kiểu C.

+2

Trên thực tế, 'static_cast' cũng có thể dẫn đến hoạt động thời gian chạy, giống như diễn viên kiểu c có thể (ví dụ: khi bạn truyền từ dấu phẩy động sang số nguyên và ngược lại). – MikeMB

+1

Tại sao nên sử dụng 'static_cast' để chuyển đổi giữa dấu phẩy động và số nguyên? Bạn chỉ có thể gán: 'double d = 5; int i = d; '. Chuyển đổi có thể bao gồm chi phí thời gian chạy, nhưng bạn phải trả chi phí đó ngay cả khi bạn không viết 'static_cast'. –

+1

Có các ngữ cảnh, trong đó không cho phép thu hẹp chuyển đổi tiềm ẩn (ví dụ:khởi tạo danh sách) hoặc nơi bạn muốn thực hiện chuyển đổi rõ ràng. Ví dụ. để chọn một quá tải hoặc tài liệu nhất định (cho bạn hoặc trình biên dịch) mà bạn biết về chuyển đổi đang diễn ra. Ngoài ra, chuyển đổi float sang int chỉ là một ví dụ - suy nghĩ của toán tử chuyển đổi rõ ràng/constructors của lớp hoặc lên/xuống đúc một con trỏ trong một hệ thống phân cấp, với nhiều thừa kế. – MikeMB

1

Sự thật kinh điển là lắp ráp, vì vậy hãy thử cả hai và xem bạn có nhận được logic khác không.

Nếu bạn nhận được cùng một cụm chính xác, không có sự khác biệt - không thể có. Nơi duy nhất bạn thực sự cần phải gắn bó với các phôi C cũ là trong các thường trình C và thư viện thuần túy, ở đây không có ý nghĩa gì khi giới thiệu sự phụ thuộc C++ chỉ cho việc nhập kiểu.

Một điều cần lưu ý là các phôi xảy ra khắp nơi trong một đoạn mã có kích thước phù hợp. Trong toàn bộ sự nghiệp của tôi, tôi chưa bao giờ tìm kiếm "tất cả các phôi" trong một đoạn logic - bạn có xu hướng tìm kiếm các phôi tới một TYPE cụ thể như 'A' và tìm kiếm trên "(A)" thường hiệu quả như một cái gì đó như "static_cast <A>". Sử dụng các phôi mới hơn cho những thứ như xác nhận loại và như vậy, không phải vì chúng tạo các tìm kiếm mà bạn sẽ không bao giờ làm dễ dàng hơn.

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