dễ bay hơi so với có thể thay đổi trong C ++


85

Tôi có một câu hỏi về sự khác biệt giữa dễ bay hơi và có thể thay đổi. Tôi nhận thấy rằng cả hai đều có nghĩa là nó có thể được thay đổi. Còn gì nữa? Họ là những điều tương tự? Có gì khác biệt? Chúng được áp dụng ở đâu? Tại sao hai ý tưởng được đề xuất? Làm thế nào để sử dụng chúng theo cách khác nhau?

Cảm ơn rất nhiều.

Câu trả lời:


112

Một mutabletrường có thể được thay đổi ngay cả trong một đối tượng được truy cập thông qua một constcon trỏ hoặc tham chiếu, hoặc trong một constđối tượng, do đó trình biên dịch biết không lưu trữ nó trong bộ nhớ R / O. Một volatilevị trí là một trong đó có thể thay đổi theo mã trình biên dịch không biết về (ví dụ như một số tài xế kernel cấp), do đó trình biên dịch biết không để tối ưu hóa ví dụ như đăng ký giao giá trị mà theo giả định không hợp lệ mà giá trị "không thể nào có đã thay đổi "kể từ khi nó được tải lần cuối trong sổ đăng ký đó. Các loại thông tin rất khác nhau được cung cấp cho trình biên dịch để ngăn chặn các loại tối ưu hóa không hợp lệ khác nhau.


13
volatilecác đối tượng cũng có thể bị thay đổi bởi các quy trình không liên quan đến CPU. Ví dụ, một thanh ghi nhận byte trong thiết bị ngoại vi truyền thông có thể tự tăng lên khi nhận byte (và điều này thậm chí có thể kích hoạt ngắt). Một ví dụ khác là thanh ghi cờ ngắt đang chờ xử lý trong một thiết bị ngoại vi.
Mike DeSimone

55
Ngoài ra, volatilekhông chỉ có nghĩa là đối tượng có thể thay đổi bên ngoài kiến ​​thức của trình biên dịch - nó còn có nghĩa là việc ghi vào đối tượng không thể bị trình biên dịch loại bỏ ngay cả khi những ghi đó dường như vô dụng. Ví dụ: x = 1; x = 0; nếu xlà biến, trình biên dịch phải phát ra cả hai hoạt động ghi (có thể quan trọng ở cấp phần cứng). Tuy nhiên, đối với một đối tượng không bay hơi, trình biên dịch có thể chọn không bận tâm đến việc viết 1vì nó chưa bao giờ được sử dụng.
Michael Burr

15
Một đối tượng có thể được đánh dấu cả constvolatile! Bạn không thể thay đổi đối tượng, nhưng nó có thể được thay đổi sau lưng bạn.
CTMacUser

2
@Destructor: tình huống thông thường là ghi vào thanh ghi thiết bị phần cứng.
Michael Burr

5
@Destructor giả sử bạn đang kiểm soát trạng thái của đèn LED. Viết 0 là TẮT, viết 1 là BẬT. Nếu tôi cần nhấp nháy đèn LED để thông báo một số trạng thái lỗi, nhưng trình biên dịch quyết định tối ưu hóa tất cả các lần ghi ngoại trừ lần ghi cuối cùng, vì không có giá trị nào được sử dụng, thì đèn LED không bao giờ nhấp nháy và hành vi tôi mong muốn không được thực hiện .
iheanyi

28

mutable: Từ khóa có thể thay đổi ghi đè bất kỳ câu lệnh const đi kèm nào. Một thành viên có thể thay đổi của một đối tượng const có thể được sửa đổi.

volatile: Từ khóa variable là một công cụ sửa đổi phụ thuộc vào việc triển khai, được sử dụng khi khai báo các biến, điều này ngăn trình biên dịch tối ưu hóa các biến đó. Biến động nên được sử dụng với các biến có giá trị có thể thay đổi theo những cách không mong muốn (tức là thông qua một ngắt), điều này có thể xung đột với các tối ưu hóa mà trình biên dịch có thể thực hiện.

Nguồn


bạn nói Volatile should be used with variables whose value can change in unexpected wayschúng ta có nên sử dụng nó ngẫu nhiên không?
Asif Mushtaq

@AsifMushtaq không phải giá trị. các cách. tác động có thể thay đổi các hoán vị mà mã bạn viết có. Vì vậy, bạn có thể truy cập biến thông qua tham chiếu const ptr hoặc const. Điều gì xảy ra nếu nó không phải là mã của bạn thay đổi nó? Một cái gì đó trình biên dịch không thể kiểm tra ptr hoặc loại tham chiếu của? Đó là sự dễ bay hơi. Và tính dễ bay hơi cũng buộc bộ nhớ cache ghi trở lại bộ nhớ chính. Vì vậy, điều này được sử dụng một LOT với mã đa luồng. :)
Dan

22

Chúng chắc chắn KHÔNG giống nhau. Có thể thay đổi tương tác với const. Nếu bạn có một con trỏ const, bạn thường không thể thay đổi thành viên. Mutable cung cấp một ngoại lệ cho quy tắc đó.

Mặt khác, dễ thay đổi hoàn toàn không liên quan đến những thay đổi của chương trình. Nó có nghĩa là bộ nhớ có thể thay đổi vì những lý do ngoài tầm kiểm soát của trình biên dịch, do đó trình biên dịch phải đọc hoặc ghi địa chỉ bộ nhớ mọi lúc và không thể lưu nội dung vào một thanh ghi.


"Mặt khác, dễ bay hơi hoàn toàn không liên quan đến những thay đổi do chương trình thực hiện ..." - hmmm, hãy làm cho một thành viên dễ bay hơi và xem những gì bị hỏng trong quá trình biên dịch. Cố gắng thêm biến sau thực tế cũng giống như cố thêm const sau thực tế ... Đau đớn.
jww

@jww: Nó hoàn toàn không liên quan đến các bài viết do chương trình tạo ra. Bạn có thể lấy địa chỉ của một loại đối tượng T, lưu trữ nó vào một const T*và đọc từ nó. Nếu bạn tạo đối tượng đó volatile, việc lưu trữ địa chỉ của nó vào const T*sẽ không thành công, mặc dù bạn không bao giờ cố gắng viết. volatilevà các thay đổi / sửa đổi / ghi bộ nhớ từ mã chương trình là hoàn toàn trực giao.
Ben Voigt

17

Một cách nghĩ thô thiển nhưng hiệu quả về sự khác biệt là:

  • Trình biên dịch biết khi nào một đối tượng có thể thay đổi thay đổi.
  • Trình biên dịch không thể biết khi nào một đối tượng dễ bay hơi thay đổi.

1
Trong mạch đó: volatilebytes_renition, mutablereference_count.
Mike DeSimone

11

Một biến được đánh dấu mutablecho phép nó được sửa đổi trong một phương thức được khai báo const.

Một biến được đánh dấu sẽ volatilecho trình biên dịch biết rằng nó phải đọc / ghi biến mỗi khi mã của bạn nói với nó (tức là nó không thể tối ưu hóa quyền truy cập vào biến).


4

Tôi muốn nói thêm rằng dễ bay hơi cũng rất hữu ích khi xử lý các ứng dụng đa luồng, tức là bạn có luồng chính (nơi main () sống) và bạn sinh ra một luồng công nhân sẽ tiếp tục quay trong khi một biến "app_running" là true. main () kiểm soát xem "app_running" là đúng hay sai, vì vậy nếu bạn không thêm thuộc tính biến động vào khai báo "app_running", nếu trình biên dịch tối ưu hóa quyền truy cập vào "app_running" trong mã do luồng phụ chạy, main ( ) có thể thay đổi "app_running" thành false nhưng luồng phụ sẽ tiếp tục chạy vì giá trị đã được lưu vào bộ nhớ đệm. Tôi đã thấy hành vi tương tự khi sử dụng gcc trên Linux và VisualC ++. Một thuộc tính "dễ bay hơi" được đưa vào khai báo "app_running" đã giải quyết được vấn đề. Vì thế,


1
Không! Đây là một sự hiểu lầm phổ biến. C ++ 11 và C11 đã giới thiệu nguyên tử cho mục đích này stackoverflow.com/questions/8819095/…
KristianR
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.