ความแตกต่างระหว่าง const int *, const int * const และ int const * คืออะไร


1356

ฉันมักจะเลอะวิธีการใช้งานconst int*, const int * constและint const *อย่างถูกต้อง มีชุดของกฎที่กำหนดสิ่งที่คุณสามารถทำได้และทำไม่ได้?

ฉันต้องการรู้สิ่งที่ควรทำและสิ่งที่ไม่ควรทำในแง่ของการมอบหมายผ่านไปยังฟังก์ชั่นอื่น ๆ


175
คุณสามารถใช้"กฎตามเข็มนาฬิกา / กฎเกลียว"เพื่อถอดรหัสการประกาศ C และ C ++ ส่วนใหญ่
James McNellis

52
cdecl.orgเป็นเว็บไซต์ที่ยอดเยี่ยมที่แปลการประกาศ C ให้คุณโดยอัตโนมัติ
Dave Gallagher

6
@Calmarius: เริ่มต้นที่ประเภทชื่อ / ควรจะย้ายไปทางขวาเมื่อคุณสามารถซ้ายเมื่อคุณต้อง int *(*)(char const * const). เริ่มต้นไปทางขวาของวงเล็บแล้วเราจะต้องเลื่อนไปทางซ้าย:* pointerข้างนอก parens เราสามารถเลื่อนไปทางขวา: pointer to function of .... จากนั้นเราต้องเลื่อนไปทางซ้าย: pointer to function of ... that returns pointer to int. ทำซ้ำเพื่อขยายพารามิเตอร์ (คน):... pointer to function of (constant pointer to constant char) that returns pointer to intการประกาศหนึ่งบรรทัดที่เทียบเท่าในภาษาที่อ่านง่ายเช่น Pascal คืออะไร
Mark K Cowan

1
@MarkKCowan ใน Pascal มันจะเป็นอะไรที่เหมือนfunction(x:^char):^intกัน มีฟังก์ชั่นประเภทที่บ่งบอกถึงตัวชี้ไปยังฟังก์ชั่นดังนั้นจึงไม่จำเป็นต้องระบุและ Pascal ไม่บังคับใช้ความถูกต้อง const สามารถอ่านจากซ้ายไปขวา
Calmarius

5
สิ่งแรกทางซ้ายของ "const" คือค่าคงที่ ถ้า "const" เป็นสิ่งที่อยู่ไกลไปทางซ้ายที่สุดสิ่งแรกที่อยู่ทางขวาของมันคือค่าคงที่
Cupcake

คำตอบ:


2208

อ่านข้างหลัง (ตามที่ขับเคลื่อนโดยกฎเข็มนาฬิกา / หมุนวน ):

  • int* - ตัวชี้ไปยัง int
  • int const * - ตัวชี้ไปยัง const int
  • int * const - ตัวชี้ const ไปยัง int
  • int const * const - ตัวชี้ const เพื่อ const int

ตอนนี้คนแรกconstสามารถอยู่ทั้งสองข้างของประเภทดังนั้น:

  • const int * == int const *
  • const int * const == int const * const

ถ้าคุณอยากจะบ้าจริง ๆ คุณสามารถทำสิ่งนี้:

  • int ** - ตัวชี้ไปยังตัวชี้ไปยัง int
  • int ** const - ตัวชี้ const ไปยังตัวชี้ไปยัง int
  • int * const * - ตัวชี้ไปยังตัวชี้ const ไปยัง int
  • int const ** - ตัวชี้ไปยังตัวชี้ไปยัง const int
  • int * const * const - ตัวชี้ const ไปยังตัวชี้ const ไปยัง int
  • ...

และเพื่อให้แน่ใจว่าเรามีความชัดเจนในความหมายของconst:

int a = 5, b = 10, c = 15;

const int* foo;     // pointer to constant int.
foo = &a;           // assignment to where foo points to.

/* dummy statement*/
*foo = 6;           // the value of a can´t get changed through the pointer.

foo = &b;           // the pointer foo can be changed.



int *const bar = &c;  // constant pointer to int 
                      // note, you actually need to set the pointer 
                      // here because you can't change it later ;)

*bar = 16;            // the value of c can be changed through the pointer.    

/* dummy statement*/
bar = &a;             // not possible because bar is a constant pointer.           

fooเป็นตัวชี้ตัวแปรไปยังจำนวนเต็มคงที่ สิ่งนี้ช่วยให้คุณเปลี่ยนสิ่งที่คุณชี้ไป แต่ไม่ใช่ค่าที่คุณชี้ไป ส่วนใหญ่มักจะนี้จะเห็นกับสตริง const charC-สไตล์ที่คุณต้องชี้ไปที่ คุณสามารถเปลี่ยนสตริงที่คุณชี้ไป แต่คุณไม่สามารถเปลี่ยนเนื้อหาของสตริงเหล่านี้ได้ สิ่งนี้มีความสำคัญเมื่อสตริงตัวเองอยู่ในส่วนข้อมูลของโปรแกรมและไม่ควรเปลี่ยน

barเป็นตัวชี้ค่าคงที่หรือคงที่เป็นค่าที่สามารถเปลี่ยนแปลงได้ นี่เป็นเหมือนข้อมูลอ้างอิงที่ไม่มีน้ำตาลประโยคพิเศษ เนื่องจากความจริงนี้โดยปกติคุณจะใช้การอ้างอิงที่คุณจะใช้T* constตัวชี้เว้นแต่คุณจะต้องอนุญาตพNULLอยน์เตอร์


481
ฉันต้องการผนวกกฎง่ายๆที่อาจช่วยให้คุณจำวิธีการค้นพบว่า 'const' ใช้กับตัวชี้หรือชี้ข้อมูล: แยกคำสั่งที่เครื่องหมายดอกจันแล้วถ้าคำหลัก const ปรากฏในส่วนด้านซ้าย (เช่นใน 'const int * foo') - มันเป็นข้อมูลชี้ถ้ามันอยู่ในส่วนที่ถูกต้อง ('int * const bar') - มันเกี่ยวกับตัวชี้
Michael

14
@Michael: Kudos ถึง Michael สำหรับกฎง่ายๆสำหรับการจดจำ / ทำความเข้าใจกฎ const
sivabudh

10
@ Jeffrey: อ่านย้อนหลังได้ดีตราบใดที่ไม่มีวงเล็บ จากนั้นก็ดี ... ใช้ typedefs
Mooing Duck

12
+1 แม้ว่าจะมีข้อสรุปที่ดีกว่า: อ่านการประกาศตัวชี้ไปข้างหลังนั่นหมายความว่าใกล้กับคำสั่งของ @Michael: หยุดการอ่านซ้ายไปขวาตามปกติที่เครื่องหมายดอกจันแรก
Wolf

3
@gedamial มันทำงานได้ดี แต่คุณต้องกำหนดในเวลาเดียวกันกับที่คุณประกาศ (เพราะคุณไม่สามารถกำหนด "ตัวชี้ const" ใหม่ได้) const int x = 0; const int *const px = &x; const int *const *const p = &px;ทำงานได้ดี
RastaJedi

356

สำหรับผู้ที่ไม่ทราบเกี่ยวกับเข็มนาฬิกา / เกลียวกฎ: เริ่มต้นจากชื่อของตัวแปรย้าย clockwisely (ในกรณีนี้ย้ายไปข้างหลัง) ต่อไปชี้หรือประเภท ทำซ้ำจนกระทั่งการแสดงออกสิ้นสุดลง

นี่คือตัวอย่าง:

ตัวชี้ไปยัง int

ตัวชี้ const เพื่อ int const

ตัวชี้ไปยัง const const

ตัวชี้ไปยัง const int

ตัวชี้ const เพื่อ int


8
@ ม.ค. ลิงก์สำหรับตัวอย่างที่ซับซ้อนไม่มีสิทธิ์ใช้งาน คุณสามารถโพสต์ได้โดยตรงที่นี่หรือลบข้อ จำกัด ในการดู?
R71

8
@Rog มันเคยมีสิทธิ์การเข้าถึงแบบเปิดทั้งหมด ... ฉันไม่ได้เขียนบทความและไม่มีสิทธิ์การเข้าถึงด้วยตัวเองโชคไม่ดี อย่างไรก็ตามนี่เป็นบทความรุ่นเก่าที่ยังใช้งานได้: archive.is/SsfMX
Jan Rüegg

8
ตัวอย่างที่ซับซ้อนยังคงเป็นจากขวาไปซ้าย แต่รวมถึงการแก้ไขวงเล็บตามปกติ สิ่งที่หมุนวนตามเข็มนาฬิกาทั้งหมดไม่ได้ทำให้ง่ายขึ้น
Matthew อ่าน

4
ตัวอย่างที่ดีที่สุด: void (*signal(int, void (*fp)(int)))(int);จาก archive.is/SsfMX
naXa

3
อย่าพึ่งพากฎนี้ นี่ไม่ใช่สากล มีบางกรณีที่มันล้มเหลว
haccks

150

ฉันคิดว่าทุกอย่างมีคำตอบที่นี่แล้ว แต่ฉันแค่ต้องการเพิ่มว่าคุณควรระวังtypedefs! มันไม่ใช่แค่การแทนที่ข้อความ

ตัวอย่างเช่น:

typedef char *ASTRING;
const ASTRING astring;

ประเภทของการastringเป็นไม่ได้char * const const char *นี่คือหนึ่งในเหตุผลที่ฉันมักจะวางconstด้านขวาของประเภทและไม่เริ่มต้น


20
และสำหรับฉันนี่คือเหตุผลที่ไม่เคยพิมพ์พอยน์เตอร์พอยน์เตอร์ ฉันไม่เห็นประโยชน์ในสิ่งต่าง ๆ เช่นtypedef int* PINT(ฉันคิดว่ามันเป็นสิ่งที่มาจากการฝึกฝนใน C และนักพัฒนาจำนวนมากยังคงทำมันอยู่) เยี่ยมมากฉันแทนที่มัน*ด้วย a Pมันไม่ได้เพิ่มความเร็วในการพิมพ์รวมทั้งแนะนำปัญหาที่คุณพูดถึง
Mephane

1
@Mephane - ฉันเห็นได้ว่า อย่างไรก็ตามสำหรับฉันแล้วดูเหมือนว่าจะย้อนกลับเพื่อหลีกเลี่ยงการใช้ภาษาที่ดีเพื่อที่จะใช้กฎการสร้างประโยคพิเศษ (เกี่ยวกับการจัดวาง "const") แทนที่จะหลีกเลี่ยงการใช้กฎไวยากรณ์พิเศษเพื่อให้คุณสามารถใช้คุณลักษณะภาษานี้ได้อย่างปลอดภัย .
TED

6
@Mephane PINTเป็นการใช้ typedef ที่ค่อนข้างโง่โดยเฉพาะเพราะว่ามันทำให้ฉันคิดว่าระบบร้านค้าใช้เบียร์เพื่อความจำ แม้ว่า typedef จะค่อนข้างมีประโยชน์สำหรับการจัดการกับพอยน์เตอร์ของฟังก์ชัน
ApproachingDarknessFish

5
@KazDragon ขอบคุณ! ไม่ว่าฉันจะได้ messed ขึ้นกับทุกคนที่ typedefed PVOID, LPTSTRสิ่งที่อยู่ใน Win32 API!
David Lee

2
@Mephane: ฉันต้องใช้ pSomething สองสามครั้งเมื่อใช้มาโครรุ่นเก่าซึ่งเขียนขึ้นเพื่อรับประเภท แต่จะแยกกันถ้าประเภทนั้นไม่ใช่ตัวระบุตัวเลขและตัวอักษรเดียว :)
Groo

56

เหมือนทุกคนที่ชี้ให้เห็น:

คือสิ่งที่แตกต่างระหว่างconst X* p, X* const pและconst X* const p?

คุณต้องอ่านคำประกาศของตัวชี้จากขวาไปซ้าย

  • const X* p หมายถึง "p ชี้ไปที่ X นั่นคือ const": ไม่สามารถเปลี่ยนวัตถุ X ผ่าน p

  • X* const p หมายถึง "p เป็นตัวชี้ const เป็น X ที่ไม่ใช่ const": คุณไม่สามารถเปลี่ยนตัวชี้ p เองได้ แต่คุณสามารถเปลี่ยนวัตถุ X ผ่าน p

  • const X* const p หมายถึง "p เป็นตัวชี้ const เป็น X ที่เป็น const": คุณไม่สามารถเปลี่ยนตัวชี้ p เองได้และไม่สามารถเปลี่ยนวัตถุ X ผ่าน p


3
อย่าลืมว่าconst X* p;== X const * p;ดังใน"p points to an X that is const": the X object can't be changed via p.
Jesse Chisholm

การอธิบายที่ง่ายและดี!
Edison Lo

50
  1. การอ้างอิงอย่างต่อเนื่อง:

    การอ้างอิงถึงตัวแปร (นี่คือ int) ซึ่งเป็นค่าคงที่ เราส่งผ่านตัวแปรเป็นการอ้างอิงส่วนใหญ่เนื่องจากการอ้างอิงมีขนาดเล็กกว่าค่าจริง แต่มีผลข้างเคียงและนั่นเป็นเพราะมันเป็นเหมือนนามแฝงของตัวแปรจริง เราอาจเปลี่ยนตัวแปรหลักโดยไม่ตั้งใจผ่านการเข้าถึงนามแฝงอย่างสมบูรณ์ดังนั้นเราจึงทำให้ค่าคงที่เพื่อป้องกันผลข้างเคียงนี้

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
  2. พอยน์เตอร์คงที่

    เมื่อตัวชี้คงที่ชี้ไปที่ตัวแปรแล้วจะไม่สามารถชี้ไปที่ตัวแปรอื่น ๆ ได้

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
  3. ตัวชี้เป็นค่าคงที่

    ตัวชี้ที่สิ่งใดไม่สามารถเปลี่ยนค่าของตัวแปรที่เรียกว่าพอยน์เตอร์เป็นค่าคงที่

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
  4. ตัวชี้ค่าคงที่เป็นค่าคงที่

    ตัวชี้ค่าคงที่เป็นค่าคงที่คือตัวชี้ที่ไม่สามารถเปลี่ยนที่อยู่ที่ชี้ไปและไม่สามารถเปลี่ยนค่าที่เก็บไว้ที่ที่อยู่นั้นได้

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error

20

กฎทั่วไปก็คือconstคำหลักจะนำไปใช้กับสิ่งที่นำหน้ามันทันที ข้อยกเว้นการเริ่มต้นconstใช้กับสิ่งที่ตามมา

  • const int*เป็นเช่นเดียวกับint const*และวิธีการ"ชี้ไปยัง int คงที่"
  • const int* constเป็นเช่นเดียวกับint const* constและวิธีการ"ชี้อย่างต่อเนื่องเพื่อ int คงที่"

แก้ไข: สำหรับ Dos และ Don'ts หากคำตอบนี้ไม่เพียงพอคุณจะแม่นยำมากขึ้นเกี่ยวกับสิ่งที่คุณต้องการ?


19

คำถามนี้แสดงให้เห็นอย่างชัดเจนว่าทำไมฉันถึงชอบทำสิ่งต่าง ๆ ในแบบที่ฉันพูดถึงในคำถามของฉันคือ const หลังจากยอมรับ id ประเภท?

ในระยะสั้นฉันพบวิธีที่ง่ายที่สุดในการจำกฎคือ "const" ดำเนินไปตามสิ่งที่บังคับใช้ ดังนั้นในคำถามของคุณ "int const *" หมายความว่า int คงที่ในขณะที่ "int * const" จะหมายถึงตัวชี้คงที่

หากมีคนตัดสินใจที่จะวางไว้ที่ด้านหน้า (เช่น: "const int *") เป็นข้อยกเว้นพิเศษในกรณีนั้นมันจะใช้กับสิ่งที่อยู่หลังมัน

หลายคนชอบใช้ข้อยกเว้นพิเศษนั้นเพราะพวกเขาคิดว่ามันดูดีกว่า ฉันไม่ชอบเพราะมันเป็นข้อยกเว้นและทำให้สิ่งต่าง ๆ สับสน


2
ฉันขาดเรื่องนี้ เหตุผลมันทำให้รู้สึก อย่างไรก็ตามนักพัฒนา c ++ ส่วนใหญ่จะเขียนconst T*และมันก็เป็นธรรมชาติมากขึ้น คุณเคยใช้T* constanyways บ่อยแค่ไหนการอ้างอิงจะทำได้ดี ผมได้รับบิตโดยทั้งหมดนี้เพียงครั้งเดียวเมื่อต้องการและแทนที่จะเขียนboost::shared_ptr<const T> const boost::shared_ptr<T>ปัญหาเดียวกันในบริบทที่แตกต่างกันเล็กน้อย
ราคาแมตต์

ที่จริงฉันใช้ตัวชี้คงที่บ่อยกว่าการใช้ค่าคงที่ นอกจากนี้คุณต้องคิดว่าคุณจะมีปฏิกิริยาอย่างไรต่อหน้าพอยน์เตอร์ต่อพอยน์เตอร์ (ฯลฯ ) เป็นที่ยอมรับว่าเป็นสิ่งที่หายาก แต่มันก็เป็นการดีที่จะคิดถึงสิ่งต่าง ๆ ในแบบที่คุณสามารถรับมือกับสถานการณ์เหล่านี้ด้วย applomb
TED

1
ข้อดีอีกข้อหนึ่งของการวาง const ที่ด้านขวาของประเภทคือตอนนี้ทุกอย่างทางด้านซ้ายconstคือประเภทของ const ที่เป็นและทุกอย่างทางด้านขวาคือที่ซึ่งเป็น const จริง ๆ ใช้int const * const * p;เป็นตัวอย่าง ไม่ฉันไม่ปกติเขียนแบบนั้นนี่เป็นเพียงตัวอย่าง ครั้งแรกconst: ชนิด int และ int ที่ const เป็นเนื้อหาของตัวชี้ const pที่มีเนื้อหาของ const สอง: type คือตัวชี้ไปยังconstint, const oblect คือเนื้อหาของp
dgnuff

18

constการใช้งานที่เรียบง่ายของ

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

const int Constant1=96; 

จะสร้างค่าคงที่จำนวนเต็มซึ่งเรียกอย่างไม่น่าเชื่อ Constant1ด้วยค่า 96

ค่าคงที่ดังกล่าวมีประโยชน์สำหรับพารามิเตอร์ที่ใช้ในโปรแกรม แต่ไม่จำเป็นต้องเปลี่ยนหลังจากที่คอมไพล์โปรแกรมแล้ว มันมีข้อได้เปรียบสำหรับโปรแกรมเมอร์มากกว่า C preprocessor#defineคำสั่งซึ่งเป็นที่เข้าใจ & ใช้โดยคอมไพเลอร์เองไม่เพียง แต่แทนที่ลงในข้อความของโปรแกรมโดย preprocessor ก่อนถึงคอมไพเลอร์หลักดังนั้นข้อความแสดงข้อผิดพลาดจึงมีประโยชน์มากกว่า

นอกจากนี้ยังใช้งานได้กับพอยน์เตอร์ด้วย แต่ต้องระวังconstว่าจะใช้พอยน์เตอร์หรือชี้ไปที่อะไรหรือไม่ ตัวอย่างเช่น:

const int * Constant2 

ประกาศว่าConstant2เป็นตัวชี้ตัวแปรเป็นจำนวนเต็มคงที่และ:

int const * Constant2

เป็นไวยากรณ์ทางเลือกซึ่งทำเช่นเดียวกันในขณะที่

int * const Constant3

ประกาศว่าConstant3เป็นตัวชี้คงที่เป็นจำนวนเต็มตัวแปรและ

int const * const Constant4

ประกาศว่าConstant4เป็นตัวชี้คงที่เป็นจำนวนเต็มคงที่ โดยทั่วไป 'const' จะใช้กับสิ่งใดก็ตามที่อยู่ทางด้านซ้ายของมัน (นอกเหนือจากหากไม่มีสิ่งใดในกรณีนี้

อ้างอิง: http://duramecho.com/ComputerInformation/WhyHowCppConst.html


9

ฉันมีข้อสงสัยเหมือนกันกับคุณจนกระทั่งฉันเจอหนังสือเล่มนี้โดย C ++ Guru Scott Meyers constโปรดดูรายการที่สามในหนังสือเล่มนี้ที่เขาพูดในรายละเอียดเกี่ยวกับการใช้

เพียงทำตามคำแนะนำนี้

  1. หากคำconstปรากฏขึ้นทางด้านซ้ายของเครื่องหมายดอกจันสิ่งที่ชี้ไปยังนั้นคงที่
  2. หากคำconstปรากฏขึ้นทางด้านขวาของเครื่องหมายดอกจันตัวชี้จะคงที่
  3. หากconstปรากฏบนทั้งสองด้านทั้งสองจะคงที่

7

มันง่าย แต่ยุ่งยาก โปรดทราบว่าเราสามารถสลับconstรอบคัดเลือกกับชนิดของข้อมูลใด ๆ ( int, char,floatฯลฯ )

ลองดูตัวอย่างด้านล่าง


const int *p==> *pเป็นแบบอ่านอย่างเดียว [ pคือตัวชี้ไปยังจำนวนเต็มคงที่]

int const *p==> *pเป็นแบบอ่านอย่างเดียว [ pคือตัวชี้ไปยังจำนวนเต็มคงที่]


int *p const==> คำชี้แจงที่ผิด คอมไพเลอร์พ่นข้อผิดพลาดทางไวยากรณ์

int *const p==> pเป็นแบบอ่านอย่างเดียว [ pเป็นตัวชี้ค่าคงที่จำนวนเต็ม] เนื่องจากตัวชี้pที่นี่เป็นแบบอ่านอย่างเดียวการประกาศและการกำหนดควรอยู่ในที่เดียวกัน


const int *p const ==> คำชี้แจงที่ผิด คอมไพเลอร์พ่นข้อผิดพลาดทางไวยากรณ์

const int const *p ==> *pเป็นแบบอ่านอย่างเดียว

const int *const p1 ==> *pและpอ่านได้อย่างเดียว [ pเป็นตัวชี้ค่าคงที่จำนวนเต็มคงที่] เนื่องจากตัวชี้pที่นี่เป็นแบบอ่านอย่างเดียวการประกาศและการกำหนดควรอยู่ในที่เดียวกัน


int const *p const ==> คำชี้แจงที่ผิด คอมไพเลอร์พ่นข้อผิดพลาดทางไวยากรณ์

int const int *p ==> คำชี้แจงที่ผิด คอมไพเลอร์พ่นข้อผิดพลาดทางไวยากรณ์

int const const *p ==> *pเป็นแบบอ่านอย่างเดียวและเทียบเท่าint const *p

int const *const p ==> *pและpอ่านได้อย่างเดียว [ pเป็นตัวชี้ค่าคงที่จำนวนเต็มคงที่] เนื่องจากตัวชี้pที่นี่เป็นแบบอ่านอย่างเดียวการประกาศและการกำหนดควรอยู่ในที่เดียวกัน


6

มีจุดที่ลึกซึ้งอื่น ๆ อีกมากมายโดยรอบความถูกต้อง const ใน C ++ ฉันคิดว่าคำถามที่นี่เป็นเพียงเกี่ยวกับ C แต่ฉันจะให้ตัวอย่างที่เกี่ยวข้องเนื่องจากแท็กคือ C ++:

  • คุณมักจะผ่านข้อโต้แย้งขนาดใหญ่เช่นสตริงTYPE const &ที่ป้องกันไม่ให้วัตถุถูกดัดแปลงหรือคัดลอก ตัวอย่าง:

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    แต่TYPE & constไม่มีความหมายเพราะมีการอ้างอิงเสมอ

  • คุณควรติดป้ายกำกับวิธีการเรียนที่ไม่ได้แก้ไขชั้นเรียนเป็นconstมิฉะนั้นคุณไม่สามารถเรียกวิธีการจากการTYPE const &อ้างอิง ตัวอย่าง:

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • มีสถานการณ์ทั่วไปที่ทั้งค่าส่งคืนและเมธอดควรเป็น const ตัวอย่าง:

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    ในความเป็นจริงวิธีการ const จะต้องไม่ส่งคืนข้อมูลคลาสภายในเป็นการอ้างอิงถึงไม่ใช่แบบ const

  • เป็นผลให้หนึ่งมักจะต้องสร้างทั้ง const และวิธีการที่ไม่ใช่ const โดยใช้การบรรทุกเกินพิกัด ตัวอย่างเช่นหากคุณกำหนดT const& operator[] (unsigned i) const;คุณอาจต้องการเวอร์ชันที่ไม่ใช่ const ซึ่งกำหนดโดย:

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

ตัวอย่าง, ไม่มีฟังก์ชัน const ใน C, ฟังก์ชั่นที่ไม่ใช่สมาชิกไม่สามารถเป็น const ใน C ++ ได้, เมธอด const อาจมีผลข้างเคียงและคอมไพเลอร์ไม่สามารถใช้ฟังก์ชัน const เพื่อหลีกเลี่ยงการเรียกใช้ฟังก์ชันซ้ำ ในความเป็นจริงแม้แต่การint const &อ้างอิงอย่างง่าย ๆอาจเป็นพยานถึงคุณค่าของการอ้างอิงที่เปลี่ยนแปลง


6

ไวยากรณ์การประกาศ C และ C ++ ได้รับการอธิบายซ้ำ ๆ ว่าเป็นการออกแบบที่ล้มเหลวโดยนักออกแบบดั้งเดิม

ให้ตั้งชื่อ “ pointer to Type” แทน; ฉันจะเรียกมันว่าPtr_:

template< class Type >
using Ptr_ = Type*;

ตอนนี้เป็นตัวชี้ไปยังPtr_<char>char

Ptr_<const char>const charเป็นตัวชี้ไปยัง

และconst Ptr_<const char>เป็นตัวชี้ไปยังconstconst char

ที่นั่น

ป้อนคำอธิบายรูปภาพที่นี่


3
คุณมีคำพูดสำหรับประโยคแรกหรือไม่?
sp2danny

@ sp2danny: Googling“ C ไวยากรณ์ล้มเหลวในการทดลอง” มีเพียงการสัมภาษณ์จำนวนมากกับ Bjarne Stroustrup ซึ่งเขาแสดงความคิดเห็นของเขาในทิศทางนั้นเช่น“ ฉันพิจารณาไวยากรณ์ C declarator ของการทดลองที่ล้มเหลว” ในการสัมภาษณ์ Slashdot ดังนั้นฉันจึงไม่มีการอ้างอิงสำหรับการอ้างสิทธิ์เกี่ยวกับมุมมองของนักออกแบบดั้งเดิมของ C. ฉันคิดว่ามันสามารถพบได้โดยความพยายามในการวิจัยที่เพียงพอหรืออาจหักล้างเพียงแค่ถามพวกเขา แต่ฉันคิดว่ามันดีกว่าตอนนี้ ด้วยส่วนหนึ่งของการอ้างสิทธิ์ยังคงลังเลและเป็นจริง :)
ไชโยและ hth - Alf

1
"ไวยากรณ์การประกาศ C และ C ++ ได้รับการอธิบายซ้ำ ๆ ว่าเป็นการออกแบบที่ล้มเหลวโดยนักออกแบบดั้งเดิม" ผิดสำหรับ C โปรดเปลี่ยนประโยคของคุณเกี่ยวกับ C หรือเสนอราคา
Stargateur

3
@Stargateur: เห็นได้ชัดว่าคุณได้อ่านความคิดเห็นก่อนหน้านี้และพบสิ่งที่คุณสามารถใช้ประโยชน์จากคนอวดรู้ ขอให้โชคดีกับชีวิตของคุณ อย่างไรก็ตามตัวนับอายุอย่างฉันจำได้มากว่าเราไม่สามารถพิสูจน์ได้โดยไม่ต้องมีส่วนร่วมในการวิจัยที่ต้องใช้เวลามาก คุณสามารถใช้คำของฉัน
ไชโยและ hth - Alf


6

สำหรับฉันแล้วตำแหน่งของ constคือไม่ว่าจะปรากฏไปทางซ้ายหรือขวาหรือทั้งซ้ายและขวาเมื่อเทียบกับการ*ช่วยให้ฉันคิดออกความหมายที่แท้จริง

  1. constไปทางซ้ายของ*บ่งชี้ว่าวัตถุที่ชี้โดยตัวชี้เป็นconstวัตถุ

  2. constถึง RIGHT ของ*บ่งชี้ว่าตัวชี้เป็นconstตัวชี้

ตารางต่อไปนี้นำมาจาก Stanford CS106L Standard C ++ Programming Laboratory Course Course

ป้อนคำอธิบายรูปภาพที่นี่


3

สิ่งนี้ส่วนใหญ่เน้นที่บรรทัดที่สอง: แนวปฏิบัติที่ดีที่สุดการกำหนดพารามิเตอร์ฟังก์ชัน ฯลฯ

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

หลีกเลี่ยง const_cast <> เหมือนกาฬโรค มีกรณีการใช้งานที่ถูกต้องตามกฎหมายหนึ่งหรือสองกรณี แต่มีน้อยมากและอยู่ระหว่าง หากคุณพยายามที่จะเปลี่ยนconstวัตถุคุณจะทำสิ่งต่าง ๆ ได้ดียิ่งขึ้นเพื่อค้นหาผู้ที่ประกาศconstในจังหวะแรกและพูดคุยกับพวกเขาเพื่อให้ได้ความเห็นเป็นเอกฉันท์ว่าจะเกิดอะไรขึ้น

ซึ่งนำไปสู่การกำหนดอย่างประณีตมาก คุณสามารถกำหนดเป็นบางอย่างเฉพาะถ้าไม่ใช่แบบคงที่ หากคุณต้องการกำหนดให้เป็นสิ่งที่เป็น const ดูด้านบน จำไว้ว่าในการประกาศint const *foo;และint * const bar;สิ่งต่าง ๆ นั้นconst - คำตอบอื่น ๆ ที่นี่ได้ครอบคลุมปัญหาที่น่าชื่นชมดังนั้นฉันจะไม่เข้าไป

พารามิเตอร์ฟังก์ชั่น:

ผ่านค่า: เช่นvoid func(int param)คุณไม่สนใจทางเดียวหรืออื่น ๆ ที่เว็บไซต์โทร อาร์กิวเมนต์สามารถทำให้มีกรณีการใช้งานสำหรับการประกาศฟังก์ชั่นเป็นvoid func(int const param)แต่ที่ไม่มีผลกระทบต่อผู้โทรเพียงในฟังก์ชั่นของตัวเองในสิ่งที่ค่าใด ๆ ที่ถูกส่งผ่านไม่สามารถเปลี่ยนแปลงได้โดยฟังก์ชั่นในระหว่างการโทร

ผ่านการอ้างอิง: เช่นvoid func(int &param)ตอนนี้มันสร้างความแตกต่าง ตามที่เพิ่งประกาศfuncอนุญาตให้เปลี่ยนแปลงparamและไซต์การโทรใด ๆ ควรพร้อมที่จะรับมือกับผลที่ตามมา การเปลี่ยนแปลงการประกาศเป็นการvoid func(int const &param)เปลี่ยนแปลงสัญญาและการค้ำประกันที่funcตอนนี้ไม่สามารถเปลี่ยนแปลงได้paramซึ่งหมายถึงสิ่งที่ผ่านไปแล้วคือสิ่งที่จะกลับมา ดังที่คนอื่น ๆ สังเกตเห็นว่าสิ่งนี้มีประโยชน์มากสำหรับการส่งวัตถุขนาดใหญ่อย่างถูกที่คุณไม่ต้องการเปลี่ยน ผ่านการอ้างอิงมีราคาถูกกว่ามากผ่านวัตถุขนาดใหญ่ตามค่า

ผ่านตัวชี้: เช่นvoid func(int *param)และvoid func(int const *param)สองคนนี้จะสวยมากความหมายเหมือนกันกับคู่อ้างอิงของพวกเขาด้วยข้อแม้ที่ว่าฟังก์ชั่นที่เรียกว่าตอนนี้ต้องมีการตรวจสอบnullptrเว้นแต่บางอื่น ๆ มั่นใจสัญญารับประกันfuncว่าจะไม่ได้รับในnullptrparam

ส่วนความเห็นในหัวข้อนั้น การพิสูจน์ความถูกต้องในกรณีเช่นนี้เป็นเรื่องที่เลวร้ายมันเป็นเรื่องง่ายเกินไปที่จะทำผิดพลาด ดังนั้นอย่าเสี่ยงและตรวจสอบพารามิเตอร์ของตัวชี้nullptrเสมอ คุณจะช่วยรักษาความเจ็บปวดและความทุกข์ทรมานของตัวเองและยากที่จะหาข้อบกพร่องในระยะยาว และสำหรับค่าใช้จ่ายในการตรวจสอบก็มีราคาถูกและในกรณีที่การวิเคราะห์แบบคงที่ที่สร้างขึ้นในคอมไพเลอร์สามารถจัดการได้เครื่องมือเพิ่มประสิทธิภาพจะกำจัดมันต่อไป เปิดใช้การสร้างรหัสเชื่อมโยงเวลาสำหรับ MSVC หรือ WOPR (ฉันคิดว่า) สำหรับ GCC และคุณจะได้รับโปรแกรมอย่างกว้างขวางเช่นแม้ในการเรียกใช้ฟังก์ชันที่ข้ามขอบเขตโมดูลซอร์สโค้ด

ในตอนท้ายของวันทั้งหมดข้างต้นทำให้เป็นกรณีที่มั่นคงมากที่จะชอบการอ้างอิงถึงพอยน์เตอร์ พวกมันปลอดภัยกว่าทุกรอบ


3

const ที่มี int ทั้งสองด้านจะทำให้ตัวชี้ไปยังค่าคงที่ int :

const int *ptr=&i;

หรือ:

int const *ptr=&i;

constหลังจากนั้น*จะทำให้ตัวชี้คงที่เป็น int :

int *const ptr=&i;

ในกรณีนี้สิ่งเหล่านี้ทั้งหมดคือตัวชี้ไปยังจำนวนเต็มคงที่แต่ไม่มีสิ่งเหล่านี้เป็นตัวชี้ค่าคงที่:

 const int *ptr1=&i, *ptr2=&j;

ในกรณีนี้ทั้งหมดเป็นตัวเลขชี้ไปอย่างต่อเนื่องและ ptr2 เป็นตัวชี้คงที่ค่าคงที่จำนวนเต็ม แต่ ptr1 ไม่ใช่ตัวชี้คงที่:

int const *ptr1=&i, *const ptr2=&j;

3
  • ถ้าconstอยู่ทางซ้ายของ*มันหมายถึงค่า (ไม่สำคัญว่าจะเป็นconst intหรือint const)
  • ถ้าconstเป็นไปทางขวาของ*มันหมายถึงตัวชี้ตัวเอง
  • มันสามารถเป็นได้ทั้งสองอย่างในเวลาเดียวกัน

จุดสำคัญ: const int *p ไม่ได้หมายความว่าคุณค่าที่คุณอ้างถึงนั้นคงที่ !! . หมายความว่าคุณไม่สามารถเปลี่ยนผ่านตัวชี้นั้นได้ (หมายถึงคุณไม่สามารถกำหนด $ * p = ... `) มูลค่าตัวเองอาจมีการเปลี่ยนแปลงในวิธีอื่น เช่น

int x = 5;
const int *p = &x;
x = 6; //legal
printf("%d", *p) // prints 6
*p = 7; //error 

สิ่งนี้มีไว้เพื่อใช้เป็นส่วนใหญ่ในฟังก์ชันลายเซ็นเพื่อรับประกันว่าฟังก์ชันไม่สามารถเปลี่ยนอาร์กิวเมนต์ที่ส่งผ่านโดยไม่ตั้งใจได้


2

เพียงเพื่อความสมบูรณ์สำหรับ C ตามคำอธิบายอื่น ๆ ไม่แน่ใจสำหรับ C ++

  • pp - ตัวชี้ไปยังตัวชี้
  • p - ตัวชี้
  • ข้อมูล - สิ่งที่ชี้ไปในตัวอย่าง x
  • ตัวหนา - ตัวแปรอ่านอย่างเดียว

ชี้

  • ข้อมูล p - int *p;
  • ข้อมูล p -int const *p;
  • ข้อมูลp -int * const p;
  • ข้อมูลp -int const * const p;

ตัวชี้ไปยังตัวชี้

  1. ข้อมูล pp p - int **pp;
  2. ข้อมูลpp p -int ** const pp;
  3. ข้อมูลpp p -int * const *pp;
  4. ข้อมูล pp p -int const **pp;
  5. ข้อมูลpp p -int * const * const pp;
  6. ข้อมูลpp p -int const ** const pp;
  7. ข้อมูล pp p -int const * const *pp;
  8. ข้อมูลpp p -int const * const * const pp;
// Example 1
int x;
x = 10;
int *p = NULL;
p = &x;
int **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 2
int x;
x = 10;
int *p = NULL;
p = &x;
int ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 3
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 4
int const x = 10; // Definition must happen during declaration
int const * p = NULL;
p = &x;
int const **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 5
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 6
int const x = 10; // Definition must happen during declaration
int const *p = NULL;
p = &x;
int const ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 7
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 8
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

N-levels ของ Dereference

แค่เดินต่อไป แต่มนุษยชาติอาจคว่ำบาตรคุณ

int x = 10;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;
int ****pppp = &ppp;

printf("%d \n", ****pppp);

0
  1. const int*- ตัวชี้ไปยังintวัตถุคงที่

คุณสามารถเปลี่ยนค่าของตัวชี้; คุณไม่สามารถเปลี่ยนค่าของintวัตถุตัวชี้ชี้ไปที่


  1. const int * const- ตัวชี้คงที่ไปยังintวัตถุคงที่

คุณไม่สามารถเปลี่ยนค่าของตัวชี้หรือค่าของintวัตถุที่ตัวชี้ชี้ไป


  1. int const *- ตัวชี้ไปยังintวัตถุคงที่

คำสั่งนี้เทียบเท่ากับ 1 const int*- คุณสามารถเปลี่ยนค่าของตัวชี้ได้ แต่คุณไม่สามารถเปลี่ยนค่าของintวัตถุได้ตัวชี้จะชี้ไปที่


จริงๆแล้วมีตัวเลือกที่ 4 คือ

  1. int * const- ตัวชี้คงที่กับintวัตถุ

คุณสามารถเปลี่ยนค่าของวัตถุที่ตัวชี้ชี้ไป แต่คุณไม่สามารถเปลี่ยนค่าของตัวชี้ได้ ตัวชี้จะชี้ไปที่intวัตถุเดียวกันเสมอแต่ค่าของintวัตถุนี้สามารถเปลี่ยนแปลงได้


หากคุณต้องการกำหนดโครงสร้าง C หรือ C ++ บางประเภทคุณสามารถใช้กฎเข็มนาฬิกา / หมุนวนที่สร้างโดย David Anderson; แต่อย่าสับสนกับกฎของแอนเดอร์สันที่ผลิตโดย Ross J. Anderson ซึ่งเป็นสิ่งที่ค่อนข้างชัดเจน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.