Hằng số có thể cải thiện hiệu suất không?


92

Tôi đã đọc nhiều lần rằng việc thực thi hằng số đúng trong mã C hoặc C ++ của bạn không chỉ là một phương pháp hay về khả năng bảo trì mà còn có thể cho phép trình biên dịch của bạn thực hiện tối ưu hóa. Tuy nhiên, tôi cũng đã đọc được điều hoàn toàn ngược lại - rằng nó không ảnh hưởng đến hiệu suất cả.

Do đó, bạn có ví dụ nào mà tính đúng của const có thể hỗ trợ trình biên dịch của bạn cải thiện hiệu suất chương trình của bạn không?


50
Hằng số đúng là một trong những phương pháp TỐT NHẤT liên quan đến khả năng bảo trì. Nếu mã C ++ của bạn không phải là const-đúng, thì về cơ bản nó là một đống tào lao, đang chờ thảm họa ập đến. Nó không nhằm mục đích ảnh hưởng đến hiệu suất.

2
@Neil Butterworth: tiếc là điều ngược lại không đúng.
Beta

6
Đây là một ví dụ constđã tạo ra sự khác biệt về hiệu suất: stackoverflow.com/questions/1121791/… . Tuy nhiên, về cơ bản đây là một vấn đề về chất lượng triển khai. constkhông xác định được liệu trình biên dịch có thể thực hiện tối ưu hóa một cách hợp pháp hay không, nó chỉ xảy ra rằng phiên bản của trình biên dịch không thực hiện được khi nó bị thiếu.
Steve Jessop

3
Tôi khá chắc "morgennebel" đã bỏ sót một từ 'duy nhất' trong câu đầu tiên: Nó có ý nghĩa hơn nhiều với "is not only a good practice".
IanH

2
@IanH Vâng, tôi đã cân nhắc điều đó. Nhưng OP đã có nhiều thời gian để làm rõ. Tôi thực sự bị đánh dấu bởi những người đăng câu hỏi và sau đó đơn giản là biến mất.

Câu trả lời:


77

consttính đúng đắn không thể cải thiện hiệu suất bởi vì const_castmutablebằng ngôn ngữ và cho phép mã phá vỡ các quy tắc một cách phù hợp. Điều này thậm chí còn tồi tệ hơn trong C ++ 11, nơi constdữ liệu của bạn có thể là một con trỏ tới a std::atomic, nghĩa là trình biên dịch phải tôn trọng những thay đổi được thực hiện bởi các luồng khác.

Điều đó nói rằng, việc trình biên dịch xem xét mã mà nó tạo ra và xác định xem nó có thực sự ghi vào một biến nhất định hay không, và áp dụng các tối ưu hóa cho phù hợp.

Điều đó nói lên tất cả, consttính đúng đắn là một điều tốt đối với khả năng bảo trì. Nếu không, các khách hàng của lớp bạn có thể phá vỡ các thành viên nội bộ của lớp đó. Ví dụ, hãy xem xét tiêu chuẩn std::string::c_str()- nếu nó không thể trả về giá trị const, bạn có thể sử dụng bộ đệm bên trong của chuỗi!

Không sử dụng constvì lý do hiệu suất. Sử dụng nó vì lý do bảo trì.


31
"bạn có thể vặn với bộ đệm bên trong của chuỗi!" - quan trọng là bạn có thể vô tình vặn xung quanh bộ đệm bên trong. Lỗi trình biên dịch là do constbiển chỉ dẫn, nói rằng, "bạn đang làm điều gì đó ngu ngốc".
Steve Jessop

4
... và const-casts là những biển chỉ dẫn nói rằng "tác giả của mã này đang cố gắng làm điều gì đó thông minh" ;-)
Steve Jessop

5
@Steve Jessop - hoặc const-cast là các biển chỉ dẫn cho biết "Tôi đang cố gắng bổ sung một nhóm mã const-đúng thành một nhóm không const-đúng và tôi không thể sửa một trong hai". Điều này, để tôi nói với bạn, không có cách nào thông minh, chỉ gây khó chịu.
Michael Kohne

7
@Michael - vâng, điểm công bằng. Có lẽ biển chỉ dẫn ban đầu không phải là "bạn đang làm điều gì đó ngu ngốc", mà là "ai đó đang làm điều gì đó ngu ngốc".
Steve Jessop

Godbolt và Arduino nói với tôi rằng tính đúng của const không chỉ để giải trí.
dgrat 14/09/17

31

Có nó có thể.

Hầu hết các consts hoàn toàn vì lợi ích của lập trình viên và không giúp trình biên dịch tối ưu hóa bởi vì việc loại bỏ chúng là hợp pháp và vì vậy chúng không cho trình biên dịch biết bất kỳ điều gì hữu ích cho việc tối ưu hóa. Tuy nhiên, một số constkhông thể (hợp pháp) bị loại bỏ và chúng cung cấp cho trình biên dịch thông tin hữu ích để tối ưu hóa.

Ví dụ: quyền truy cập vào một biến toàn cục được xác định với một constkiểu có thể được nội dòng trong khi một biến không có constkiểu không thể được nội dòng vì nó có thể thay đổi trong thời gian chạy.

https://godbolt.org/g/UEX4NB

C ++:

int foo1 = 1;
const int foo2 = 2;

int get_foo1() {
    return foo1;
}

int get_foo2() {
    return foo2;
}

asm:

foo1:
        .long   1
foo2:
        .long   2
get_foo1():
        push    rbp
        mov     rbp, rsp
        mov     eax, DWORD PTR foo1[rip] ; foo1 must be accessed by address
        pop     rbp
        ret
get_foo2():
        push    rbp
        mov     rbp, rsp
        mov     eax, 2 ; foo2 has been replaced with an immediate 2
        pop     rbp
        ret

Về mặt thực tế, hãy nhớ rằng mặc dù constcó thể cải thiện hiệu suất, nhưng trong hầu hết các trường hợp, nó sẽ không hoặc có nhưng thay đổi sẽ không đáng chú ý. Tính hữu ích chính của constkhông phải là tối ưu hóa.


Steve Jessop đưa ra một ví dụ khác trong nhận xét của anh ấy về câu hỏi ban đầu, điều này dẫn đến một điều đáng nói. Trong phạm vi khối, trình biên dịch có thể suy luận xem một biến có bị đột biến hay không và tối ưu hóa cho phù hợp, bất kể const, bởi vì trình biên dịch có thể thấy tất cả các công dụng của biến. Ngược lại, trong ví dụ trên, không thể đoán được liệu foo1có bị đột biến hay không vì nó có thể được sửa đổi trong các đơn vị dịch khác. Tôi cho rằng một trình biên dịch siêu biên dịch có tri giác giả định có thể phân tích toàn bộ chương trình và xác định xem nó có hợp lệ để truy cập nội tuyến vào foo1... nhưng các trình biên dịch thực không thể.


@ericcurtin Đó là lý do tại sao tôi không đề cập đến trình biên dịch trong câu trả lời. Thông thường, khi đăng assembly được tạo, tôi phải đảm bảo nêu rõ trình biên dịch và phiên bản, nhưng đây là một tối ưu hóa mà mọi trình biên dịch tối ưu hóa chính sẽ thực hiện vì vậy tôi không muốn tạo ấn tượng rằng điều này là riêng cho một trình biên dịch.
Praxeolitic

1
@Acorn Đây là ví dụ tương tự nhưng với một đối tượng lớp: godbolt.org/z/R-Zfgc . Ngoài ra, các biến trong ví dụ có liên kết bên ngoài.
Praxeolitic

6

theo kinh nghiệm của tôi, không

Đối với các biến vô hướng, trình biên dịch có thể xác định bất cứ khi nào giá trị được thay đổi và tự thực hiện tối ưu hóa cần thiết.

Đối với con trỏ mảng, tính đúng của const không đảm bảo rằng các giá trị thực sự không đổi khi có các vấn đề về răng cưa tiềm ẩn. Do đó, trình biên dịch không thể chỉ sử dụng công cụ sửa đổi const để thực hiện tối ưu hóa

nếu bạn đang tìm kiếm sự tối ưu hóa, bạn nên xem xét __restrict__hoặc các công cụ sửa đổi / thuộc tính chức năng đặc biệt: http://gcc.gnu.org/onlineocs/gcc/Function-Attributes.html


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.