ก่อนอื่นเราต้องกลับไปที่ความหมายของการส่งผ่านมูลค่าและโดยการอ้างอิง
สำหรับภาษาอย่าง Java และ SML การส่งผ่านค่าจะตรงไปตรงมา (และไม่มีการอ้างอิงผ่าน) เช่นเดียวกับการคัดลอกค่าตัวแปรเนื่องจากตัวแปรทั้งหมดเป็นเพียงสเกลาร์และมีความหมายในการคัดลอกในตัว พิมพ์ใน C ++ หรือ "การอ้างอิง" (พอยน์เตอร์ที่มีชื่อและไวยากรณ์ต่างกัน)
ใน C เรามีสเกลาร์และประเภทที่ผู้ใช้กำหนด:
- สเกลาร์มีค่าตัวเลขหรือนามธรรม (ตัวชี้ไม่ใช่ตัวเลข แต่มีค่านามธรรม) ที่คัดลอก
- ประเภทการรวมมีสมาชิกเริ่มต้นที่อาจถูกคัดลอกทั้งหมด:
- สำหรับประเภทผลิตภัณฑ์ (อาร์เรย์และโครงสร้าง): เรียกซ้ำสมาชิกทั้งหมดของโครงสร้างและองค์ประกอบของอาร์เรย์จะถูกคัดลอก (ไวยากรณ์ของฟังก์ชั่น C ไม่สามารถส่งผ่านอาร์เรย์ได้ด้วยมูลค่าโดยตรงเฉพาะสมาชิกอาร์เรย์ของ struct แต่นั่นเป็นรายละเอียด )
- สำหรับประเภทรวม (สหภาพ): ค่าของ "สมาชิกที่ใช้งาน" จะถูกเก็บไว้; เห็นได้ชัดว่าการคัดลอกสมาชิกโดยสมาชิกไม่ได้เป็นไปตามลำดับเนื่องจากไม่สามารถเริ่มสมาชิกทั้งหมดได้
ในประเภท C ++ ที่ผู้ใช้กำหนดสามารถมีความหมายของการคัดลอกที่ผู้ใช้กำหนดซึ่งช่วยให้การเขียนโปรแกรม "เชิงวัตถุ" อย่างแท้จริงด้วยวัตถุที่เป็นเจ้าของทรัพยากรและการดำเนินการ "คัดลอกลึก" ในกรณีเช่นนี้การทำสำเนาเป็นการเรียกฟังก์ชั่นที่เกือบจะสามารถดำเนินการตามอำเภอใจได้
สำหรับ C structs ที่คอมไพล์เป็น C ++ "การคัดลอก" ยังคงถูกกำหนดเป็นการเรียกการดำเนินการคัดลอกที่ผู้ใช้กำหนด มันหมายความว่าความหมายของโปรแกรมย่อยทั่วไป C / C ++ แตกต่างกันใน C และ C ++: ใน C ประเภทรวมทั้งหมดจะถูกคัดลอกใน C ++ ฟังก์ชั่นการคัดลอกที่สร้างขึ้นโดยปริยายจะถูกเรียกให้คัดลอกสมาชิกแต่ละคน ผลลัพธ์ที่ได้คือว่าในกรณีใดกรณีหนึ่งสมาชิกแต่ละคนจะถูกคัดลอก
(มีข้อยกเว้นฉันคิดว่าเมื่อคัดลอกโครงสร้างภายในสหภาพ)
ดังนั้นสำหรับประเภทคลาสวิธีเดียว (การคัดลอกภายนอกสหภาพ) เพื่อสร้างอินสแตนซ์ใหม่คือผ่านตัวสร้าง (แม้สำหรับผู้ที่สร้างคอมไพเลอร์เล็กน้อยที่สร้างคอนสตรัคเตอร์)
คุณไม่สามารถใช้ที่อยู่ของ rvalue ผ่านโอเปอเรเตอร์ unary &
แต่นั่นไม่ได้หมายความว่าไม่มีวัตถุ rvalue และวัตถุตามคำนิยามมีที่อยู่ ; และที่อยู่นั้นยังแสดงด้วยโครงสร้างไวยากรณ์: วัตถุประเภทคลาสสามารถสร้างได้โดยตัวสร้างเท่านั้นและมีthis
ตัวชี้ แต่สำหรับประเภทเล็ก ๆ น้อย ๆ ไม่มีคอนสตรัคเตอร์ที่ผู้ใช้เขียนดังนั้นไม่มีสถานที่ที่จะวางthis
จนกระทั่งหลังจากที่สำเนาถูกสร้างและตั้งชื่อ
สำหรับประเภทสเกลาร์ค่าของวัตถุคือ rvalue ของวัตถุซึ่งเป็นค่าทางคณิตศาสตร์ล้วนที่เก็บไว้ในวัตถุ
สำหรับประเภทของคลาสความคิดเพียงอย่างเดียวของค่าของวัตถุก็คืออีกสำเนาของวัตถุซึ่งสามารถสร้างได้โดยตัวสร้างสำเนาซึ่งเป็นฟังก์ชันที่แท้จริง สร้างโดยไม่เรียกตัวสร้าง) นั่นหมายความว่ามูลค่าของวัตถุที่เป็นผลมาจากการเปลี่ยนแปลงของรัฐโปรแกรมทั่วโลกโดยการประหาร มันไม่สามารถเข้าถึงทางคณิตศาสตร์ได้
ดังนั้นผ่านค่าจริงๆไม่ได้เป็นสิ่ง: มันผ่านสำเนาโทรคอนสตรัคซึ่งน้อยสวย ตัวสร้างสำเนาคาดว่าจะดำเนินการ "คัดลอก" ที่เหมาะสมตามความหมายที่เหมาะสมของประเภทวัตถุโดยเคารพค่าคงที่ภายใน (ซึ่งเป็นคุณสมบัติผู้ใช้ที่เป็นนามธรรมไม่ใช่คุณสมบัติ C ++ ภายใน)
ผ่านค่าของวัตถุคลาสหมายความว่า:
- สร้างอีกตัวอย่าง
- จากนั้นให้ฟังก์ชันที่เรียกใช้กระทำกับอินสแตนซ์นั้น
โปรดทราบว่าปัญหาไม่มีอะไรเกี่ยวข้องกับการคัดลอกตัวเองเป็นวัตถุที่มีที่อยู่: พารามิเตอร์ฟังก์ชั่นทั้งหมดเป็นวัตถุและมีที่อยู่ (ที่ระดับความหมายของภาษา)
ปัญหาคือว่า:
- การคัดลอกเป็นวัตถุใหม่ที่เริ่มต้นด้วยค่าทางคณิตศาสตร์ที่บริสุทธิ์ (ค่าความบริสุทธิ์ที่แท้จริง) ของวัตถุดั้งเดิมเช่นเดียวกับสเกลาร์
- หรือสำเนาเป็นค่าของวัตถุต้นฉบับเช่นเดียวกับคลาส
ในกรณีของประเภทคลาสที่ไม่สำคัญคุณยังสามารถกำหนดสมาชิกของสมาชิกสำเนาของต้นฉบับได้ดังนั้นคุณจะได้กำหนดค่า rvalue ที่แท้จริงของต้นฉบับเนื่องจากความสำคัญของการดำเนินการคัดลอก (ตัวสร้างสำเนาและการมอบหมาย) ไม่เช่นนั้นด้วยฟังก์ชั่นผู้ใช้พิเศษโดยพลการ: ค่าของต้นฉบับจะต้องเป็นสำเนาที่สร้างขึ้น
วัตถุระดับจะต้องสร้างโดยผู้โทร; ตัวสร้างอย่างเป็นทางการมีthis
ตัวชี้ แต่เป็นพิธีไม่เกี่ยวข้องที่นี่: วัตถุทั้งหมดอย่างเป็นทางการมีที่อยู่ แต่เฉพาะผู้ที่ได้รับจริงที่อยู่ของพวกเขาใช้ในรูปแบบที่ไม่ใช่ท้องถิ่นอย่างหมดจด (เหมือน*&i = 1;
ซึ่งคือการใช้ในท้องถิ่นอย่างหมดจดของที่อยู่) จำเป็นที่จะต้องมีการกำหนดไว้อย่างดี ที่อยู่
วัตถุจะต้องผ่านที่อยู่อย่างสมบูรณ์หากปรากฏว่ามีที่อยู่ในทั้งสองฟังก์ชันที่รวบรวมแยกต่างหาก:
void callee(int &i) {
something(&i);
}
void caller() {
int i;
callee(i);
something(&i);
}
ที่นี่แม้ว่าsomething(address)
จะเป็นฟังก์ชั่นบริสุทธิ์หรือมาโครหรืออะไรก็ตาม (เช่นprintf("%p",arg)
) ที่ไม่สามารถจัดเก็บที่อยู่หรือสื่อสารกับหน่วยงานอื่นเรามีความต้องการที่จะผ่านที่อยู่เพราะที่อยู่จะต้องกำหนดไว้อย่างดีสำหรับวัตถุint
ที่ไม่ซ้ำกัน เอกลักษณ์
เราไม่ทราบว่าฟังก์ชั่นภายนอกจะเป็น "บริสุทธิ์" ในแง่ของที่อยู่ที่ส่งไปยังมันหรือไม่
ที่นี่มีศักยภาพสำหรับการใช้ที่อยู่ที่แท้จริงทั้งในตัวสร้างที่ไม่สำคัญหรือ destructor ทางด้านผู้โทรอาจเป็นเหตุผลของการใช้เส้นทางที่ปลอดภัยเรียบง่ายและให้วัตถุในตัวตนของผู้โทรและผ่านที่อยู่ของมัน ตรวจสอบให้แน่ใจว่ามีการใช้ที่อยู่ที่ไม่ใช่เรื่องไร้สาระในตัวสร้างหลังจากการก่อสร้างและใน destructor ที่สอดคล้องกัน: this
ต้องปรากฏเป็นเหมือนกันกับการมีอยู่ของวัตถุ
Constructor ที่ไม่สำคัญหรือ destructor เช่นเดียวกับฟังก์ชั่นอื่น ๆ สามารถใช้this
ตัวชี้ในลักษณะที่ต้องการความสม่ำเสมอมากกว่าค่าของมันแม้ว่าวัตถุบางตัวที่มีสิ่งที่ไม่น่าสนใจอาจไม่:
struct file_handler { // don't use that class!
file_handler () { this->fileno = -1; }
file_handler (int f) { this->fileno = f; }
file_handler (const file_handler& rhs) {
if (this->fileno != -1)
this->fileno = dup(rhs.fileno);
else
this->fileno = -1;
}
~file_handler () {
if (this->fileno != -1)
close(this->fileno);
}
file_handler &operator= (const file_handler& rhs);
};
โปรดทราบว่าในกรณีนั้นแม้จะมีการใช้ตัวชี้อย่างชัดเจน (ไวยากรณ์ชัดเจนthis->
) ตัวตนของวัตถุนั้นไม่เกี่ยวข้อง: คอมไพเลอร์สามารถใช้การคัดลอกวัตถุในระดับบิตเพื่อย้ายและทำ "คัดลอก elision" นี้จะขึ้นอยู่กับระดับของ "ความบริสุทธิ์" ของการใช้งานthis
ในฟังก์ชั่นสมาชิกพิเศษ (ที่อยู่ไม่หนี)
แต่ความบริสุทธิ์ไม่ได้เป็นแอตทริบิวต์ที่มีอยู่ในระดับประกาศมาตรฐาน (ส่วนขยายของคอมไพเลอร์อยู่ที่คำอธิบายเพิ่มความบริสุทธิ์ไม่ใช่การประกาศฟังก์ชันอินไลน์) ดังนั้นคุณจะไม่สามารถกำหนด ABI ขึ้นอยู่กับความบริสุทธิ์ของรหัสที่อาจไม่สามารถใช้ได้ (รหัสอาจจะหรือ อาจไม่อินไลน์และพร้อมสำหรับการวิเคราะห์)
ความบริสุทธิ์นั้นวัดได้ว่าเป็น "บริสุทธิ์อย่างแน่นอน" หรือ "ไม่บริสุทธิ์หรือไม่ทราบ" พื้นดินทั่วไปหรือขอบเขตสูงสุดของความหมาย (สูงสุดจริง) หรือ LCM (ตัวคูณร่วมน้อย) คือ "ไม่ทราบ" ดังนั้น ABI จึงไม่ทราบ
สรุป:
- การสร้างบางอย่างต้องการคอมไพเลอร์เพื่อกำหนดเอกลักษณ์ของวัตถุ
- ABI ถูกกำหนดในรูปแบบของคลาสของโปรแกรมและไม่ใช่กรณีเฉพาะที่อาจเหมาะสมที่สุด
การทำงานในอนาคตที่เป็นไปได้:
หมายเหตุประกอบความบริสุทธิ์มีประโยชน์เพียงพอที่จะทำให้เป็นมาตรฐานและเป็นมาตรฐานหรือไม่