เวกเตอร์ถูกส่งผ่านไปยังฟังก์ชันตามค่าหรือโดยการอ้างอิงใน C ++


97

ฉันกำลังเขียนโค้ดใน C ++ ถ้าฉันมีฟังก์ชันบางอย่างvoid foo(vector<int> test)และฉันเรียกมันในโปรแกรมของฉันเวกเตอร์จะถูกส่งต่อด้วยค่าหรือการอ้างอิงหรือไม่? ฉันไม่แน่ใจเพราะฉันรู้ว่าเวกเตอร์และอาร์เรย์มีความคล้ายคลึงกันและฟังก์ชันที่ต้องการvoid bar(int test[])จะผ่านการทดสอบโดยการอ้างอิง (ตัวชี้?) แทนที่จะเป็นค่า ฉันเดาว่าฉันจะต้องส่งเวกเตอร์ด้วยตัวชี้ / การอ้างอิงอย่างชัดเจนหากฉันต้องการหลีกเลี่ยงการส่งผ่านค่า แต่ฉันไม่แน่ใจ


5
C ++ มีความหมาย "pass by value" ดังนั้นจึงส่งผ่านค่า คุณสามารถตัดสินใจที่จะส่งต่อโดยอ้างอิงได้ ทางเลือกขึ้นอยู่กับสิ่งที่ฟังก์ชันทำ
juanchopanza

2
ใช้โดยการอ้างอิงหากคุณไม่ต้องการให้ฟังก์ชันเปลี่ยนเนื้อหาเวกเตอร์ทำให้เป็น const คนอื่น ๆ ก็แค่ส่งผ่านโดยการอ้างอิง จะหลีกเลี่ยงการทำสำเนาที่ไม่ต้องการและมีราคาแพง (บางครั้ง)
Ali Kazmi

3
นอกจากนี้การอ้างอิงไม่ใช่ตัวชี้
ครัวซองต์ Paramagnetic

2
@AliKazmi ยกเว้นถ้าคุณต้องการสำเนาในเนื้อหาของฟังก์ชัน
juanchopanza

ขึ้นอยู่กับสิ่งที่คุณต้องการบรรลุ บางครั้งการใช้ตัวชี้อัจฉริยะมาตรฐานอย่างใดอย่างหนึ่งก็มีประโยชน์เช่นหากคุณต้องการส่งต่อความเป็นเจ้าของให้ใช้ unique_ptr แต่โดยปกติแล้วฉันส่งผ่าน std :: vector โดยอ้างอิง
Erik Alapää

คำตอบ:


136

ถ้าให้เดาก็คงบอกได้ว่าคุณมาจากพื้นหลัง Java นี่คือ C ++ และสิ่งต่างๆจะถูกส่งผ่านด้วยค่าเว้นแต่คุณจะระบุเป็นอย่างอื่นโดยใช้&-operator (โปรดทราบว่าตัวดำเนินการนี้ยังใช้เป็นตัวดำเนินการ 'address-of' แต่ในบริบทที่แตกต่างกัน) ทั้งหมดนี้ได้รับการบันทึกไว้เป็นอย่างดี แต่ฉันจะทบทวนซ้ำ:

void foo(vector<int> bar); // by value
void foo(vector<int> &bar); // by reference (non-const, so modifiable inside foo)
void foo(vector<int> const &bar); // by const-reference

คุณยังสามารถเลือกที่จะส่งตัวชี้ไปยังเวกเตอร์ ( void foo(vector<int> *bar)) แต่ถ้าคุณไม่ทราบว่าคุณกำลังทำอะไรอยู่และคุณรู้สึกว่านี่เป็นวิธีที่จะไปจริงๆอย่าทำ

นอกจากนี้เวกเตอร์ไม่เหมือนกับอาร์เรย์! ภายในเวกเตอร์จะติดตามอาร์เรย์ที่จัดการกับการจัดการหน่วยความจำให้คุณ แต่คอนเทนเนอร์ STL อื่น ๆ ก็เช่นกัน คุณไม่สามารถส่งผ่านเวกเตอร์ไปยังฟังก์ชันที่คาดว่าจะมีตัวชี้หรืออาร์เรย์หรือในทางกลับกัน (คุณสามารถเข้าถึง (ตัวชี้ไปที่) อาร์เรย์พื้นฐานและใช้สิ่งนี้ เวกเตอร์เป็นคลาสที่มีฟังก์ชันการทำงานมากมายผ่านฟังก์ชันสมาชิกในขณะที่ตัวชี้และอาร์เรย์เป็นประเภทที่มีอยู่แล้วภายใน นอกจากนี้เวกเตอร์ยังได้รับการจัดสรรแบบไดนามิก (ซึ่งหมายความว่าขนาดอาจถูกกำหนดและเปลี่ยนแปลงที่รันไทม์) ในขณะที่อาร์เรย์สไตล์ C จะถูกจัดสรรแบบคงที่ (ขนาดของมันคงที่และต้องทราบในเวลาคอมไพล์) ซึ่ง จำกัด การใช้งาน

ฉันขอแนะนำให้คุณอ่านเพิ่มเติมเกี่ยวกับ C ++ โดยทั่วไป (โดยเฉพาะการสลายตัวของอาร์เรย์ ) จากนั้นดูโปรแกรมต่อไปนี้ซึ่งแสดงให้เห็นความแตกต่างระหว่างอาร์เรย์และตัวชี้:

void foo1(int *arr) { cout << sizeof(arr) << '\n'; }
void foo2(int arr[]) { cout << sizeof(arr) << '\n'; }
void foo3(int arr[10]) { cout << sizeof(arr) << '\n'; }
void foo4(int (&arr)[10]) { cout << sizeof(arr) << '\n'; }

int main()
{
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    foo1(arr);
    foo2(arr);
    foo3(arr);
    foo4(arr);
}

2
ใครสามารถช่วยฉันทำความเข้าใจฟังก์ชัน foo4 การประกาศครั้งสุดท้ายได้หรือไม่ เหตุใดจึงส่งคืนขนาดของอาร์เรย์แทนที่จะเป็นขนาดของตัวชี้เหมือนในฟังก์ชันอื่น ๆ
abhishek_M

3
@abhishek_M เนื่องจากประเภทพารามิเตอร์เป็นการอ้างอิง การอ้างอิงสามารถถูกผูกไว้กับนิพจน์ประเภทเดียวกันเท่านั้น ด้วยเหตุนี้อาร์เรย์จึงไม่สลายตัวเนื่องจากการอ้างอิงไปยังอาร์เรย์ไม่สามารถผูกไว้กับตัวชี้ได้จึงสามารถผูกไว้กับอาร์เรย์ประเภทเดียวกันเท่านั้น (ในกรณีนี้คืออาร์เรย์ 10 จำนวนเต็ม)
bolov

1
c ++ 11 มี "ความหมายการย้าย" และคุณสามารถทำได้อย่างระมัดระวังและส่งผ่านค่า (ด้วยความหมายการย้าย) โดยไม่ต้องคัดลอก นี่คือลิงค์ที่ช่วยฉันได้มาก: mbevin.wordpress.com/2012/11/20/move-semantics
fchen

24

A vectorมีหน้าที่เหมือนกับอาร์เรย์ แต่สำหรับภาษาvectorเป็นประเภทและintยังเป็นประเภท สำหรับอาร์กิวเมนต์ของฟังก์ชันอาร์เรย์ประเภทใด ๆ (รวมถึงvector[]) จะถือว่าเป็นตัวชี้ A vector<int>ไม่เหมือนกับint[](ไปยังคอมไพเลอร์) vector<int>ไม่ใช่อาร์เรย์ไม่ใช่การอ้างอิงและไม่ใช่ตัวชี้ - จะถูกส่งผ่านด้วยค่าดังนั้นจึงเรียกตัวสร้างสำเนา

ดังนั้นคุณต้องใช้vector<int>&(โดยเฉพาะอย่างยิ่งกับconstถ้าฟังก์ชันไม่ได้แก้ไข) เพื่อส่งผ่านเป็นข้อมูลอ้างอิง


ไวยากรณ์สำหรับการส่ง "อาร์เรย์เวกเตอร์" โดยการอ้างอิงถึงฟังก์ชันคืออะไร?
ab123

void functionName (std :: vector <int> (& vc) [5]) {}
RIanGillis

9

void foo(vector<int> test)

เวกเตอร์จะถูกส่งผ่านด้วยค่าในสิ่งนี้

คุณมีหลายวิธีในการส่งเวกเตอร์ขึ้นอยู่กับบริบท: -

1) ผ่านการอ้างอิง: - สิ่งนี้จะช่วยให้ฟังก์ชัน foo เปลี่ยนเนื้อหาของเวกเตอร์ มีประสิทธิภาพมากกว่าการส่งผ่านค่าเนื่องจากหลีกเลี่ยงการคัดลอกเวกเตอร์

2) ผ่านการอ้างอิง const: - มีประสิทธิภาพและเชื่อถือได้เมื่อคุณไม่ต้องการให้ฟังก์ชันเปลี่ยนเนื้อหาของเวกเตอร์


1

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

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