2010-03-15 36 views
75

Tôi có 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 cả hai có nghĩa là nó có thể 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?dễ bay hơi và có thể thay đổi trong C++

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

Trả lời

96

Một lĩnh vực mutable có thể thay đổi ngay cả trong một đối tượng truy cập thông qua một con trỏ const hoặc tham chiếu, hoặc trong một đối tượng const, vì vậy trình biên dịch biết không giấu nó trong R nhớ/O. Vị trí volatile là một vị trí có thể được thay đổi bằng mã trình biên dịch không biết (ví dụ: một số trình điều khiển cấp hạt nhân), do đó trình biên dịch biết không tối ưu hóa ví dụ: đăng ký gán giá trị đó theo giả định không hợp lệ rằng giá trị "không thể thay đổi" vì nó được tải lần cuối trong thanh ghi đó. Loại thông tin rất khác nhau được cung cấp cho trình biên dịch để dừng các loại tối ưu hóa không hợp lệ khác nhau.

+12

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

+48

Ngoài ra, 'volatile' khô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ũng có nghĩa là ghi vào đối tượng không thể bị loại bỏ bởi trình biên dịch ngay cả khi những ghi đó có vẻ vô dụng. Ví dụ: 'x = 1; x = 0, 'if' x' là dễ bay hơi, trình biên dịch phải phát ra cả hai hoạt động ghi (có thể có ý nghĩa ở cấp phần cứng). Tuy nhiên, đối với một đối tượng không dễ bay hơi, trình biên dịch có thể chọn không bận tâm khi viết '1' vì nó không bao giờ được sử dụng. –

+11

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

21

Chúng chắc chắn KHÔNG giống nhau. Mutable 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 đó.

Biến động, mặt khác, hoàn toàn không liên quan đến các thay đổi được thực hiện bởi chương trình. Nó có nghĩa là bộ nhớ có thể thay đổi vì các lý do ngoài sự 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ần và không thể lưu trữ nội dung trong sổ đăng ký.

+0

* "Biến động, mặt khác, hoàn toàn không liên quan đến các thay đổi được thực hiện bởi chương trình ..." * - hmmm, làm cho thành viên dễ bay hơi và xem những gì bị hỏng trong khi biên dịch. Đang cố gắng để thêm dễ bay hơi sau khi thực tế là rất nhiều như cố gắng thêm const sau khi thực tế ... Đau đớn. – jww

+0

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

25

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

volatile: Từ khóa dễ bay hơi là công cụ sửa đổi phụ thuộc vào triển khai, được sử dụng khi khai báo biến, ngăn trình biên dịch tối ưu hóa các biến đó. Dễ bay hơi nên được sử dụng với các biến có giá trị có thể thay đổi theo cách bất ngờ (tức là thông qua ngắt), 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.

Source

+0

bạn nói 'Dễ bay hơi nên được sử dụng với các biến có giá trị có thể thay đổi theo cách bất ngờ', chúng ta có nên sử dụng nó một cách ngẫu nhiên không? – UnKnown

7

Biến được đánh dấu mutable cho phép biến được sửa đổi theo phương thức được khai báo const.

Biến được đánh dấu volatile cho 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 cho biết (nghĩa là không thể tối ưu hóa truy cập biến).

13

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

  • Trình biên dịch biết khi một thay đổi đối tượng có thể 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 tĩnh mạch đó: 'volatile' bytes_received,' mutable' reference_count. –

4

Tôi muốn thêm rằng biến động cũng rất hữu ích khi xử lý các ứng dụng đa luồng, tức là bạn có chủ đề chính (nơi chính) và bạn sinh ra một chuỗi công việc sẽ tiếp tục quay trong khi biến "app_running" là đúng. 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 dễ bay hơi 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ã chạy bởi chuỗi thứ cấp, chính () có thể thay đổi "app_running" thành false nhưng chuỗi phụ sẽ tiếp tục chạy vì giá trị đã được lưu trong bộ nhớ cache. Tôi đã thấy cùng một hành vi 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ì vậy, đây là kịch bản mà không có phần cứng ngắt hoặc hạt nhân được invoved trong việc thay đổi giá trị của các biến như vậy.

+0

Không! Đây là một sự hiểu lầm phổ biến. C++ 11 và C11 đã giới thiệu các nguyên tử cho mục đích này http://stackoverflow.com/questions/8819095/concurrency-atomic-and-volatile-in-c11-memory-model – KristianR

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