ตอนนี้เรามี std :: array แล้วสิ่งที่ใช้สำหรับอาร์เรย์สไตล์ C คืออะไร?


89

std::arrayเหนือกว่าอาร์เรย์ C อย่างมาก และแม้ว่าฉันต้องการทำงานร่วมกับรหัสเดิมฉันก็สามารถstd::array::data()ใช้ได้ มีเหตุผลใดบ้างที่ฉันต้องการอาร์เรย์แบบเก่า?

คำตอบ:


60

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

MyStruct const table[] =
{
    { something1, otherthing1 },
    //  ...
};

โดยใช้ฟังก์ชันปกติbeginและendเทมเพลต (นำมาใช้ใน C ++ 11) เพื่อทำซ้ำ โดยไม่เคยพูดถึงขนาดซึ่งคอมไพเลอร์กำหนดจากจำนวน initializers.

แก้ไข: อีกสิ่งที่ฉันลืม: ตัวอักษรสตริงยังคงเป็นอาร์เรย์สไตล์ C char[]คือมีประเภท ฉันไม่คิดว่าจะมีใครยกเว้นการใช้ตัวอักษรสตริงเพียงเพราะเรามีstd::arrayผมไม่คิดว่าทุกคนที่จะไม่รวมการใช้ตัวอักษรของสตริงเพียงเพราะเรามี


7
คุณสามารถเขียนเทมเพลตฟังก์ชันตัวแปรซึ่งสร้างอาร์เรย์โดยไม่ต้องระบุความยาว
rightfold

2
ด้วย C ++ 17 Class Template Deduction การหักอัตโนมัติจำนวนตัวเริ่มต้นได้รับการสนับสนุน ตัวอย่างเช่น "auto a = std :: array {1, 2, 3};"
Ricky65

Nitpick: ประเภทของตัวอักษรสตริงคือconst char[]
Bulletmagnet

31

ไม่ได้เอ่อพูดตรงไปตรงมา และใน 30 อักขระ

แน่นอนคุณต้องใช้อาร์เรย์ C std::arrayแต่นั่นไม่ใช่เหตุผลที่ผู้ใช้จะต้องการอาร์เรย์ C นอกจากstd::arrayนี้ไม่ไม่ได้มีประสิทธิภาพน้อยกว่าอาร์เรย์ C และมีตัวเลือกสำหรับการเข้าถึงที่ตรวจสอบขอบเขต และในที่สุดมันก็สมเหตุสมผลอย่างสมบูรณ์สำหรับโปรแกรม C ++ ใด ๆ ที่ต้องขึ้นอยู่กับไลบรารีมาตรฐานซึ่งเป็นจุดที่เป็นมาตรฐาน - และหากคุณไม่สามารถเข้าถึงไลบรารีมาตรฐานได้คอมไพเลอร์ของคุณจะไม่เป็นไปตามข้อกำหนดและ คำถามจะติดแท็ก "C ++" ไม่ใช่ "C ++ และสิ่งที่ไม่ใช่ C ++ ที่พลาดข้อกำหนดครึ่งหนึ่งเพราะรู้สึกว่าไม่เหมาะสม"


1
หืม จะเกิดอะไรขึ้นถ้าคุณกำลังเขียนโค้ด C ++ ที่เรียกจากภาษาอื่นและต้องการบางสิ่งที่จะส่งผ่านเป็นพารามิเตอร์?
asveikau

3
การใช้งานอิสระได้รับอนุญาตให้ละทิ้งไลบรารีมาตรฐานเกือบทั้งหมดและยังคงเป็นไปตามมาตรฐาน ฉันจะมีข้อสงสัยอย่างมากเกี่ยวกับคอมไพเลอร์ที่ไม่สามารถใช้งานstd::arrayในการใช้งานC ++ 11 แบบอิสระได้
Dennis Zickefoose

11
C ++ 0x Final Draft (เอกสาร N3092) § 1.4.7 "มีการกำหนดการนำไปใช้งานสองประเภท: โฮสต์และแบบอิสระสำหรับการใช้งานแบบโฮสต์มาตรฐานสากลนี้กำหนดชุดของไลบรารีที่มีอยู่การใช้งานอิสระเป็นสิ่งที่การดำเนินการอาจ เกิดขึ้นโดยไม่ได้รับประโยชน์จากระบบปฏิบัติการและมีชุดไลบรารีที่กำหนดการใช้งานซึ่งรวมถึงไลบรารีที่รองรับภาษาบางอย่าง ".. STL ไม่รวมเป็นไลบรารี" รองรับภาษา "ในคอมไพเลอร์อิสระ
Earlz

24

std::arrayดูเหมือนว่าใช้อาร์เรย์หลายมิติเป็นเรื่องง่ายกับอาร์เรย์ซีมากกว่า ตัวอย่างเช่น

char c_arr[5][6][7];

ตรงข้ามกับ

std::array<std::array<std::array<char, 7>, 6>, 5> cpp_arr;

เนื่องจากคุณสมบัติการสลายตัวอัตโนมัติของอาร์เรย์ C c_arr[i]ในตัวอย่างข้างต้นจะสลายตัวเป็นตัวชี้และคุณต้องส่งผ่านมิติข้อมูลที่เหลือเป็นพารามิเตอร์อีกสองตัว ประเด็นของฉันคือc_arrการลอกแบบไม่แพง อย่างไรก็ตามcpp_arr[i]จะมีค่าใช้จ่ายสูงมากในการคัดลอก


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

31
วิธีง่ายๆtemplate <typename T, int M, int N> using array2d = std::array<std::array<T, N>, M>;ควรแก้ปัญหาเหล่านั้น
เส้นทางไมล์

7
ตัวอย่างของคุณc_arrเป็นอย่างมากที่มีราคาแพงเพื่อคัดลอก! คุณต้องระบุรหัสเพื่อดำเนินการดังกล่าวด้วยตนเอง ตัวชี้ที่จะสลายไปนั้นมีความใกล้เคียงกับข้อมูลอ้างอิงมากกว่าสำเนาและคุณสามารถใช้std::arrayเพื่อส่งต่อข้อมูลอ้างอิงได้หากเป็นสิ่งที่คุณต้องการ
ChetS

1
@MilesRout ในทางเทคนิคไม่ควรจะstd::size_tแทนintหรือไม่? ขออภัยสำหรับ nitpicking แต่สิ่งนี้จะทำให้เป็นสากล
robbie

1
@ robbie0630 ใช่คุณทำได้size_tถ้าต้องการแม้ว่าฉันจะนึกไม่ออกว่ามีหลายสถานการณ์ที่จำเป็นต้องใช้อาร์เรย์ที่มีแถวหรือคอลัมน์มากกว่า 4 พันล้านคอลัมน์
เส้นทางไมล์

14

ดังที่ Sumant กล่าวไว้ว่าอาร์เรย์หลายมิตินั้นใช้งานง่ายกว่าด้วย C-arrays ในตัวมากกว่า std::arrayC-อาร์เรย์กว่าด้วย

เมื่อซ้อนกัน std::arrayอาจอ่านยากมากและอ่านละเอียดโดยไม่จำเป็น

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

std::array<std::array<int, 3>, 3> arr1; 

เปรียบเทียบกับ

char c_arr[3][3]; 

นอกจากนี้ทราบว่าbegin(), end()และsize()ทุกคืนค่าไม่มีความหมายเมื่อคุณรังstd::arrayทุกคืนค่าไม่มีความหมายเมื่อคุณรัง

ด้วยเหตุผลเหล่านี้ฉันได้สร้างคอนเทนเนอร์อาร์เรย์หลายมิติขนาดคงที่ของตัวเองarray_2dและarray_3d. พวกเขาคล้ายคลึงกับstd::arrayอาร์เรย์หลายมิติ 2 และ 3 มิติ ปลอดภัยกว่าและไม่มีประสิทธิภาพที่แย่ไปกว่าอาร์เรย์หลายมิติในตัว ฉันไม่ได้ใส่คอนเทนเนอร์สำหรับอาร์เรย์หลายมิติที่มีขนาดมากกว่า 3 เนื่องจากเป็นเรื่องผิดปกติ ใน C ++ 0x สามารถสร้างเทมเพลตเวอร์ชันที่แตกต่างกันซึ่งรองรับมิติข้อมูลได้ตามจำนวนที่กำหนด

ตัวอย่างของตัวแปรสองมิติ:

//Create an array 3 x 5 (Notice the extra pair of braces) 

fsma::array_2d <double, 3, 5> my2darr = {{
    { 32.19, 47.29, 31.99, 19.11, 11.19},
    { 11.29, 22.49, 33.47, 17.29, 5.01 },
    { 41.97, 22.09, 9.76, 22.55, 6.22 }
}};

ดูเอกสารฉบับเต็มได้ที่นี่:

http://fsma.googlecode.com/files/fsma.html

คุณสามารถดาวน์โหลดไลบรารีได้ที่นี่:

http://fsma.googlecode.com/files/fsma.zip


4
อาร์เรย์สไตล์ C ที่มีขนาดคงที่เป็นเรื่องง่าย แต่ถ้าคุณต้องการเปลี่ยนแปลงขนาดสิ่งต่างๆจะซับซ้อน ตัวอย่างเช่นarr[x][y]คุณไม่สามารถบอกได้ว่าarrอาร์เรย์ของอาร์เรย์อาร์เรย์ของพอยน์เตอร์ตัวชี้ไปยังอาร์เรย์หรือตัวชี้ไปยังตัวชี้ ทั้งหมดสำหรับการใช้งานนั้นถูกต้องตามกฎหมายขึ้นอยู่กับความต้องการของคุณ และอาจเป็นกรณีการใช้งานจริงส่วนใหญ่สำหรับอาร์เรย์หลายมิติจำเป็นต้องกำหนดขนาดในขณะทำงาน
Keith Thompson

ฉันชอบที่จะเห็นว่าการใช้งานอาร์เรย์ n มิติแบบตัวแปรแม่แบบ! การเขียนโปรแกรมเมตาที่ดีที่สุด!
steffen

3
@steffen ฉันพยายามไม่กี่ปีที่ผ่านมา สามารถดูได้ที่นี่code.google.com/p/fsma/source/browse/trunk/… . กรณีทดสอบที่นี่: code.google.com/p/fsma/source/browse/trunk/… . ฉันมั่นใจว่าจะทำได้ดีกว่านี้มาก
Ricky65

5

อาร์เรย์แบบ C ที่มีอยู่ใน C ++ นั้นมีความหลากหลายน้อยกว่าอาร์เรย์ C จริงมาก ความแตกต่างคือใน C ประเภทอาร์เรย์สามารถมีขนาดรันไทม์ได้ ต่อไปนี้เป็นรหัส C ที่ถูกต้อง แต่ไม่สามารถแสดงด้วยอาร์เรย์สไตล์ C ++ C หรือกับarray<>ประเภทC ++ :

void foo(int bar) {
    double tempArray[bar];
    //Do something with the bar elements in tempArray.
}

ใน C ++ คุณจะต้องจัดสรรอาร์เรย์ชั่วคราวบนฮีป:

void foo(int bar) {
    double* tempArray = new double[bar];
    //Do something with the bar elements behind tempArray.
    delete[] tempArray;
}

นี้ไม่สามารถทำได้ด้วยstd::array<>เพราะbarไม่เป็นที่รู้จักที่รวบรวมเวลาก็ต้องใช้อย่างใดอย่างหนึ่งอาร์เรย์แบบ C ใน C ++ std::vector<>หรือของ


ในขณะที่ตัวอย่างแรกสามารถแสดงใน C ++ ได้ค่อนข้างง่าย (แม้ว่าจะต้องใช้new[]และdelete[]) สิ่งต่อไปนี้ไม่สามารถทำได้ใน C ++ หากไม่มีstd::vector<>:

void smoothImage(int width, int height, int (*pixels)[width]) {
    int (*copy)[width] = malloc(height*sizeof(*copy));
    memcpy(copy, pixels, height*sizeof(*copy));
    for(y = height; y--; ) {
        for(x = width; x--; ) {
            pixels[y][x] = //compute smoothed value based on data around copy[y][x]
        }
    }
    free(copy);
}

ประเด็นคือพอยน์เตอร์ไปยังอาร์เรย์บรรทัดint (*)[width]ไม่สามารถใช้ความกว้างรันไทม์ใน C ++ ได้ซึ่งทำให้โค้ดการปรับแต่งรูปภาพมีความซับซ้อนมากขึ้นใน C ++ มากกว่าใน C การใช้งาน C ++ ทั่วไปของตัวอย่างการปรับแต่งรูปภาพจะมีลักษณะดังนี้:

void smoothImage(int width, int height, int* pixels) {
    int* copy = new int[height*width];
    memcpy(copy, pixels, height*width*sizeof(*copy));
    for(y = height; y--; ) {
        for(x = width; x--; ) {
            pixels[y*width + x] = //compute smoothed value based on data around copy[y*width + x]
        }
    }
    delete[] copy;
}

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

ฉันชอบเขียนโค้ดใน C ++ แต่เมื่อใดก็ตามที่ฉันต้องการจัดการข้อมูลหลายมิติฉันถามตัวเองจริงๆว่าฉันควรย้ายส่วนนั้นของโค้ดไปที่ C หรือไม่


7
ควรสังเกตว่าอย่างน้อย Clang และ GCC รองรับ VLA ใน C ++
Janus Troelsen

@JanusTroelsen และพวกเขาถูก จำกัด อย่างน่ากลัวว่าจะรองรับองค์ประกอบประเภทใด
rightfold

C11 ไม่ทำให้ VLA เป็นทางเลือก? ถ้าเป็นเช่นนั้นฉันคิดว่าคำตอบของคุณทำให้เข้าใจผิด มันจะถูกต้องเมื่อ C99 เป็นมาตรฐาน แต่ไม่ใช่ C11
Z boson

1
@Zboson C99 เป็นมาตรฐาน C และมีคอมไพเลอร์ที่ใช้คุณสมบัติ VLA ( gccเช่น) C11 ได้สร้างสิ่งที่น่าสนใจให้เลือกมากมายและฉันไม่คิดว่านั่นเป็นเพราะพวกเขาต้องการที่จะผิดกฎหมาย ฉันมักจะเห็นว่ามันเป็นสัญญาณว่าพวกเขาต้องการลดระดับการเขียนคอมไพเลอร์ที่เป็นไปตามมาตรฐานอย่างสมบูรณ์: VLA เป็นสัตว์ที่ค่อนข้างยากที่จะนำไปใช้และโค้ดจำนวนมากสามารถทำได้โดยไม่ต้องใช้ดังนั้นจึงเหมาะสมสำหรับคอมไพเลอร์ใหม่ในบางตัวใหม่ แพลตฟอร์มที่ไม่ต้องใช้ VLA ทันที
cmaster - คืนสถานะโมนิกา

-1

อาจจะstd::arrayไม่ช้า แต่ฉันทำการเปรียบเทียบโดยใช้การจัดเก็บอย่างง่ายและอ่านจาก std :: array; ดูผลการวัดประสิทธิภาพด้านล่าง (บน W8.1, VS2013 Update 4):

ARR_SIZE: 100 * 1000
Avrg = Tick / ARR_SIZE;

test_arr_without_init
==>VMem: 5.15Mb
==>PMem: 8.94Mb
==>Tick: 3132
==>Avrg: 0.03132
test_arr_with_init_array_at
==>VMem: 5.16Mb
==>PMem: 8.98Mb
==>Tick: 925
==>Avrg: 0.00925
test_arr_with_array_at
==>VMem: 5.16Mb
==>PMem: 8.97Mb
==>Tick: 769
==>Avrg: 0.00769
test_c_arr_without_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 358
==>Avrg: 0.00358
test_c_arr_with_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 305
==>Avrg: 0.00305

ตามเครื่องหมายลบรหัสที่ฉันใช้อยู่ใน pastebin ( ลิงค์ )

รหัสระดับมาตรฐานเป็นที่นี่ ;

ฉันไม่รู้มากเกี่ยวกับการเปรียบเทียบ ... รหัสของฉันอาจมีข้อบกพร่อง


6
ผลลัพธ์การเปรียบเทียบโดยไม่มีรหัสเปรียบเทียบหรือแฟล็กการคอมไพล์? มาเลยคุณทำได้ดีกว่า
R. Martinho Fernandes

FWIW รหัสเพียงเล็กน้อยนั้นแสดงให้เห็นแล้วว่าเกณฑ์มาตรฐานมีข้อบกพร่องอย่างรุนแรง คอมไพเลอร์ที่ฉลาดพอจะเปลี่ยนทุกอย่างให้กลายเป็นlong test_arr_without_init() { return ARR_SIZE; }
R. Martinho Fernandes

นั่นเป็นเพียงตัวอย่าง ฉันคิดว่ามันไม่ใช่เรื่องใหญ่ ฉันเปลี่ยนรหัสเพื่อส่งคืนโมฆะใช้รุ่นสร้างใน VS 2013 กับ / O2 / Ot / Gl
K'Prime

การลบค่าที่ส่งคืนหมายความว่าคอมไพเลอร์สามารถเปลี่ยนสิ่งทั้งหมดให้กลายเป็นvoid test_arr_without_init() {}ตอนนี้ได้ คุณต้องกระโดดผ่านห่วงเพื่อให้แน่ใจว่ารหัสที่คุณกำลังวัดเป็นรหัสที่คุณต้องการวัด
R.Martinho Fernandes

-5
  1. เพื่อใช้งานบางสิ่งเช่น std::array
  2. หากคุณไม่ต้องการใช้ STL หรือทำไม่ได้
  3. เพื่อประสิทธิภาพ

27
บอกฉันว่าstd::arrayจะมีประสิทธิภาพน้อยกว่าอาร์เรย์ C อย่างไร
Xeo

2
จากวิกิพีเดีย : "การติดตั้งอาร์เรย์ไม่จำเป็นต้องทำการตรวจสอบแบบผูกมัดอย่างไรก็ตามการใช้งานในบูสต์จะทำเช่นนั้นสำหรับตัวดำเนินการ [] แต่ไม่ใช่สำหรับตัวดำเนินการซ้ำ" - ดังนั้นตัวดำเนินการ [] จึงช้าลง ฉันไม่ได้ดูการใช้งาน แต่โค้ดใด ๆ ในการติดตั้งอาจขัดขวางเครื่องมือเพิ่มประสิทธิภาพ
Lou Franco

19
@Aaron McDaid: นั่นเป็นเพียงคนเดียวในat()ก็ไม่ได้อยู่ในเช่นเดียวกับoperator[] std::vectorไม่มีการลดประสิทธิภาพหรือขยายโค้ดไปstd::arrayคอมไพเลอร์ได้รับการออกแบบมาเพื่อเพิ่มประสิทธิภาพของสิ่งนี้ และแน่นอนว่าการเพิ่มฟังก์ชันที่ตรวจสอบแล้วเป็นเครื่องมือดีบักที่ยอดเยี่ยมและมีข้อได้เปรียบมากมาย @Lou Franco: รหัส C ++ ทั้งหมดอาจขึ้นอยู่กับไลบรารีมาตรฐาน - นั่นคือสิ่งที่มันมีไว้สำหรับ @Earlz: หากคุณไม่มี STL แสดงว่าไม่ใช่ C ++ และนั่นคือจุดสิ้นสุดของสิ่งนั้น
Puppy

6
@Earlz: C ++ Standard มีไลบรารีมาตรฐาน หากคุณไม่สามารถใช้ไลบรารีได้แสดงว่าไม่สอดคล้องกัน และประการที่สองคุณต้องมีคอมไพเลอร์ที่ห่วยแตกสำหรับการใช้งานstd::arrayเพื่อให้มีขนาดใหญ่กว่าการใช้งานอาร์เรย์ C ที่เทียบเท่ากัน
Puppy

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