ผันผวนและเปลี่ยนแปลงได้ใน C ++


86

ฉันมีคำถามเกี่ยวกับความแตกต่างระหว่างความผันผวนและความผันแปร ฉันสังเกตว่าทั้งสองอย่างนั้นหมายความว่ามันสามารถเปลี่ยนแปลงได้ อะไรอีก? พวกเดียวกันหรือเปล่า? อะไรคือความแตกต่าง? ใช้ได้ที่ไหน? เหตุใดจึงเสนอแนวคิดทั้งสองนี้ วิธีการใช้งานที่แตกต่างกัน?

ขอบคุณมาก.

คำตอบ:


113

mutableฟิลด์สามารถเปลี่ยนแปลงได้แม้ในวัตถุเข้าถึงได้ผ่านทางconstตัวชี้หรือการอ้างอิงหรือในconstวัตถุเป็นคอมไพเลอร์รู้ว่าไม่ต้องเก็บสะสมไว้ในหน่วยความจำ R / O volatileสถานที่หนึ่งที่สามารถเปลี่ยนแปลงได้โดยรหัสคอมไพเลอร์ไม่ทราบเกี่ยวกับ (เช่นบางเคอร์เนลไดรเวอร์ระดับ) ดังนั้นคอมไพเลอร์รู้ไม่ได้ที่จะเพิ่มประสิทธิภาพเช่นลงทะเบียนการโอนค่าที่อยู่ภายใต้สมมติฐานที่ไม่ถูกต้องว่าค่า "ไม่อาจมี เปลี่ยนแปลง "เนื่องจากโหลดครั้งสุดท้ายในรีจิสเตอร์นั้น ข้อมูลที่แตกต่างกันมากที่มอบให้กับคอมไพเลอร์เพื่อหยุดการเพิ่มประสิทธิภาพที่ไม่ถูกต้องประเภทต่างๆ


13
volatileนอกจากนี้ยังสามารถเปลี่ยนแปลงวัตถุได้โดยกระบวนการที่ไม่เกี่ยวข้องกับ CPU เลย ตัวอย่างเช่นการลงทะเบียนไบต์ที่ได้รับในอุปกรณ์ต่อพ่วงการสื่อสารสามารถเพิ่มขึ้นได้เองเมื่อได้รับไบต์ (และอาจทำให้เกิดการขัดจังหวะได้) อีกตัวอย่างหนึ่งคือการลงทะเบียนแฟล็กที่รอการขัดจังหวะในอุปกรณ์ต่อพ่วง
Mike DeSimone

56
นอกจากนี้volatileไม่เพียงหมายความว่าวัตถุสามารถเปลี่ยนแปลงภายนอกความรู้ของคอมไพเลอร์เท่านั้น แต่ยังหมายความว่าการเขียนไปยังวัตถุนั้นไม่สามารถกำจัดได้โดยคอมไพเลอร์แม้ว่าการเขียนเหล่านั้นดูเหมือนจะไร้ประโยชน์ก็ตาม ตัวอย่างเช่น: x = 1; x = 0; หากxมีความผันผวนคอมไพเลอร์จะต้องปล่อยการดำเนินการเขียนทั้งสองอย่าง (ซึ่งอาจมีนัยสำคัญในระดับฮาร์ดแวร์) อย่างไรก็ตามสำหรับวัตถุที่ไม่ลบเลือนคอมไพเลอร์สามารถเลือกที่จะไม่ยุ่งกับการเขียน1เนื่องจากไม่เคยใช้
Michael Burr

15
สามารถทำเครื่องหมายวัตถุได้ทั้งconstและvolatile! คุณไม่สามารถเปลี่ยนวัตถุ แต่สามารถเปลี่ยนด้านหลังของคุณได้
CTMacUser

2
@Destructor: สถานการณ์ปกติสำหรับการเขียนลงทะเบียนอุปกรณ์ฮาร์ดแวร์
Michael Burr

5
@Destructor สมมติว่าคุณกำลังควบคุมสถานะของ LED เขียน 0 ปิดมันเขียน 1 เปิด หากฉันต้องการแฟลช LED เพื่อสื่อสารสถานะข้อผิดพลาดบางอย่าง แต่คอมไพเลอร์ตัดสินใจที่จะปรับการเขียนทั้งหมดให้เหมาะสมยกเว้นค่าสุดท้ายเนื่องจากไม่มีการใช้ค่าใดเลย LED จะไม่กะพริบและพฤติกรรมที่ฉันต้องการจะไม่เกิดขึ้น .
iheanyi

28

mutable: คีย์เวิร์ดที่เปลี่ยนแปลงได้จะแทนที่คำสั่ง const ที่อยู่รอบ ๆ สมาชิกที่ไม่แน่นอนของวัตถุ const สามารถแก้ไขได้

volatile: คีย์เวิร์ดระเหยเป็นตัวปรับเปลี่ยนที่ขึ้นกับการใช้งานซึ่งใช้เมื่อประกาศตัวแปรซึ่งป้องกันไม่ให้คอมไพลเลอร์ปรับตัวแปรเหล่านั้นให้เหมาะสม Volatile ควรใช้กับตัวแปรที่ค่าสามารถเปลี่ยนแปลงในรูปแบบที่ไม่คาดคิด (เช่นผ่านการขัดจังหวะ) ซึ่งอาจขัดแย้งกับการเพิ่มประสิทธิภาพที่คอมไพเลอร์อาจดำเนินการ

ที่มา


คุณบอกว่าVolatile should be used with variables whose value can change in unexpected waysเราควรใช้แบบสุ่มหรือไม่?
Asif Mushtaq

@AsifMushtaq ไม่ใช่ค่า วิธี มีผลต่อการอนุญาตโค้ดที่คุณเขียน ดังนั้นคุณสามารถเข้าถึงตัวแปรผ่าน const ptr หรือการอ้างอิง const จะเกิดอะไรขึ้นถ้ารหัสของคุณไม่เปลี่ยนรหัส สิ่งที่คอมไพเลอร์ไม่สามารถตรวจสอบ ptr หรือประเภทการอ้างอิงของ? นั่นคือความผันผวน และการระเหยยังบังคับให้แคชเขียนกลับไปที่หน่วยความจำหลัก ดังนั้นจึงใช้จำนวนมากที่มีโค้ดแบบมัลติเธรด :)
แดน

22

พวกเขาไม่ใช่สิ่งเดียวกันแน่นอน ไม่สามารถโต้ตอบกับ const หากคุณมีตัวชี้ const ปกติแล้วคุณจะไม่สามารถเปลี่ยนสมาชิกได้ เปลี่ยนแปลงไม่ได้ให้ข้อยกเว้นสำหรับกฎนั้น

ในทางกลับกันความผันผวนไม่เกี่ยวข้องกับการเปลี่ยนแปลงที่เกิดขึ้นโดยโปรแกรม หมายความว่าหน่วยความจำอาจเปลี่ยนแปลงได้ด้วยเหตุผลที่อยู่นอกเหนือการควบคุมของคอมไพเลอร์ดังนั้นคอมไพเลอร์จึงต้องอ่านหรือเขียนที่อยู่หน่วยความจำทุกครั้งและไม่สามารถแคชเนื้อหาในรีจิสเตอร์ได้


"ในทางกลับกัน Volatile ไม่เกี่ยวข้องกับการเปลี่ยนแปลงที่เกิดขึ้นโดยโปรแกรม ... " - อืมทำให้สมาชิกมีความผันผวนและดูว่ามีอะไรแตกระหว่างการคอมไพล์ การพยายามเพิ่มความผันผวนหลังจากข้อเท็จจริงก็เหมือนกับการพยายามเพิ่ม const หลังจากความจริง ...
jww

@jww: มันไม่เกี่ยวข้องกับการเขียนโดยโปรแกรมเลย คุณสามารถนำที่อยู่ของออบเจ็กต์ประเภทหนึ่งTมาเก็บไว้ใน a const T*และอ่านจากมันได้ หากคุณสร้างออบเจ็กต์volatileนั้นการจัดเก็บที่อยู่ลงในconst T*จะล้มเหลวแม้ว่าคุณจะไม่เคยพยายามเขียน volatileและการเปลี่ยนแปลง / แก้ไข / หน่วยความจำที่เขียนจากโค้ดโปรแกรมจะมีมุมฉากอย่างสมบูรณ์
Ben Voigt

17

วิธีคิดเกี่ยวกับความแตกต่างที่หยาบคาย แต่มีประสิทธิภาพคือ:

  • คอมไพเลอร์รู้เมื่อวัตถุที่เปลี่ยนแปลงได้เปลี่ยนไป
  • คอมไพเลอร์ไม่สามารถทราบได้ว่าเมื่อใดที่วัตถุระเหยเปลี่ยนไป

1
ในหลอดเลือดดำนั้น: volatilebytes_received, mutablereference_count
Mike DeSimone

11

ตัวแปรที่ทำเครื่องหมายmutableอนุญาตให้แก้ไขได้ในวิธีการที่ประกาศconstไว้

ตัวแปรที่ทำเครื่องหมายvolatileบอกคอมไพเลอร์ว่าต้องอ่าน / เขียนตัวแปรทุกครั้งที่โค้ดของคุณบอกด้วยเช่นกัน (กล่าวคือไม่สามารถเพิ่มประสิทธิภาพการเข้าถึงตัวแปรออกไปได้)


4

ฉันต้องการเพิ่มว่าการระเหยยังมีประโยชน์มากเมื่อจัดการกับแอปพลิเคชันมัลติเธรดกล่าวคือคุณมีเธรดหลักของคุณ (ที่ main () มีชีวิตอยู่) และคุณวางไข่เธรดผู้ปฏิบัติงานซึ่งจะหมุนไปเรื่อย ๆ ในขณะที่ตัวแปร "app_running" เป็นจริง main () ควบคุมว่า "app_running" เป็นจริงหรือเท็จดังนั้นหากคุณไม่เพิ่มแอตทริบิวต์ระเหยในการประกาศ "app_running" หากคอมไพเลอร์เพิ่มประสิทธิภาพการเข้าถึง "app_running" ในโค้ดที่รันโดยเธรดรอง main ( ) อาจเปลี่ยน "app_running" เป็น false แต่เธรดรองจะทำงานต่อไปเนื่องจากค่าถูกแคชไว้ ฉันเห็นพฤติกรรมเดียวกันกับการใช้ gcc บน Linux และ VisualC ++ แอตทริบิวต์ "ระเหย" ที่ใส่ในการประกาศ "app_running" ช่วยแก้ปัญหาได้ ดังนั้น,


1
ไม่! นี่เป็นความเข้าใจผิดทั่วไป C ++ 11 และ C11 แนะนำอะตอมเพื่อจุดประสงค์นี้stackoverflow.com/questions/8819095/…
KristianR
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.