std::array
เหนือกว่าอาร์เรย์ C อย่างมาก และแม้ว่าฉันต้องการทำงานร่วมกับรหัสเดิมฉันก็สามารถstd::array::data()
ใช้ได้ มีเหตุผลใดบ้างที่ฉันต้องการอาร์เรย์แบบเก่า?
std::array
เหนือกว่าอาร์เรย์ C อย่างมาก และแม้ว่าฉันต้องการทำงานร่วมกับรหัสเดิมฉันก็สามารถstd::array::data()
ใช้ได้ มีเหตุผลใดบ้างที่ฉันต้องการอาร์เรย์แบบเก่า?
คำตอบ:
เว้นแต่ฉันจะพลาดอะไรบางอย่าง (ฉันไม่ได้ติดตามการเปลี่ยนแปลงล่าสุดในมาตรฐานอย่างใกล้ชิดเกินไป) การใช้อาร์เรย์สไตล์ C ส่วนใหญ่ยังคงอยู่ std::array
ไม่อนุญาตให้มีการเริ่มต้นแบบคงที่ แต่ก็ยังไม่นับตัวเริ่มต้นสำหรับคุณ และเนื่องจากก่อนหน้าstd::array
นี้มีการใช้อาร์เรย์สไตล์ C จริงเพียงอย่างเดียวสำหรับตารางที่กำหนดค่าเริ่มต้นแบบคงที่ตามแนวของ:
MyStruct const table[] =
{
{ something1, otherthing1 },
// ...
};
โดยใช้ฟังก์ชันปกติbegin
และend
เทมเพลต (นำมาใช้ใน C ++ 11) เพื่อทำซ้ำ โดยไม่เคยพูดถึงขนาดซึ่งคอมไพเลอร์กำหนดจากจำนวน initializers.
แก้ไข: อีกสิ่งที่ฉันลืม: ตัวอักษรสตริงยังคงเป็นอาร์เรย์สไตล์ C char[]
คือมีประเภท ฉันไม่คิดว่าจะมีใครยกเว้นการใช้ตัวอักษรสตริงเพียงเพราะเรามีstd::array
ผมไม่คิดว่าทุกคนที่จะไม่รวมการใช้ตัวอักษรของสตริงเพียงเพราะเรามี
const char[]
ไม่ได้เอ่อพูดตรงไปตรงมา และใน 30 อักขระ
แน่นอนคุณต้องใช้อาร์เรย์ C std::array
แต่นั่นไม่ใช่เหตุผลที่ผู้ใช้จะต้องการอาร์เรย์ C นอกจากstd::array
นี้ไม่ไม่ได้มีประสิทธิภาพน้อยกว่าอาร์เรย์ C และมีตัวเลือกสำหรับการเข้าถึงที่ตรวจสอบขอบเขต และในที่สุดมันก็สมเหตุสมผลอย่างสมบูรณ์สำหรับโปรแกรม C ++ ใด ๆ ที่ต้องขึ้นอยู่กับไลบรารีมาตรฐานซึ่งเป็นจุดที่เป็นมาตรฐาน - และหากคุณไม่สามารถเข้าถึงไลบรารีมาตรฐานได้คอมไพเลอร์ของคุณจะไม่เป็นไปตามข้อกำหนดและ คำถามจะติดแท็ก "C ++" ไม่ใช่ "C ++ และสิ่งที่ไม่ใช่ C ++ ที่พลาดข้อกำหนดครึ่งหนึ่งเพราะรู้สึกว่าไม่เหมาะสม"
std::array
ในการใช้งานC ++ 11 แบบอิสระได้
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]
จะมีค่าใช้จ่ายสูงมากในการคัดลอก
array
ไปยังฟังก์ชันได้โดยไม่สูญเสียมิติ และถ้าคุณส่งผ่านไปยังเทมเพลตฟังก์ชันฟังก์ชันนั้นอาจอนุมานได้ทั้งมิติข้อมูลและขนาดของแต่ละมิติหรือเพียงหนึ่งในสองมิติ สิ่งนี้อาจน่าสนใจสำหรับไลบรารีเทมเพลตทางวิทยาศาสตร์ที่ทำงานกับมิติที่กำหนดเองเป็นหลัก
template <typename T, int M, int N> using array2d = std::array<std::array<T, N>, M>;
ควรแก้ปัญหาเหล่านั้น
c_arr
เป็นอย่างมากที่มีราคาแพงเพื่อคัดลอก! คุณต้องระบุรหัสเพื่อดำเนินการดังกล่าวด้วยตนเอง ตัวชี้ที่จะสลายไปนั้นมีความใกล้เคียงกับข้อมูลอ้างอิงมากกว่าสำเนาและคุณสามารถใช้std::array
เพื่อส่งต่อข้อมูลอ้างอิงได้หากเป็นสิ่งที่คุณต้องการ
std::size_t
แทนint
หรือไม่? ขออภัยสำหรับ nitpicking แต่สิ่งนี้จะทำให้เป็นสากล
size_t
ถ้าต้องการแม้ว่าฉันจะนึกไม่ออกว่ามีหลายสถานการณ์ที่จำเป็นต้องใช้อาร์เรย์ที่มีแถวหรือคอลัมน์มากกว่า 4 พันล้านคอลัมน์
ดังที่ Sumant กล่าวไว้ว่าอาร์เรย์หลายมิตินั้นใช้งานง่ายกว่าด้วย C-arrays ในตัวมากกว่า std::array
C-อาร์เรย์กว่าด้วย
เมื่อซ้อนกัน 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
คุณสามารถดาวน์โหลดไลบรารีได้ที่นี่:
arr[x][y]
คุณไม่สามารถบอกได้ว่าarr
อาร์เรย์ของอาร์เรย์อาร์เรย์ของพอยน์เตอร์ตัวชี้ไปยังอาร์เรย์หรือตัวชี้ไปยังตัวชี้ ทั้งหมดสำหรับการใช้งานนั้นถูกต้องตามกฎหมายขึ้นอยู่กับความต้องการของคุณ และอาจเป็นกรณีการใช้งานจริงส่วนใหญ่สำหรับอาร์เรย์หลายมิติจำเป็นต้องกำหนดขนาดในขณะทำงาน
อาร์เรย์แบบ 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 หรือไม่
gcc
เช่น) C11 ได้สร้างสิ่งที่น่าสนใจให้เลือกมากมายและฉันไม่คิดว่านั่นเป็นเพราะพวกเขาต้องการที่จะผิดกฎหมาย ฉันมักจะเห็นว่ามันเป็นสัญญาณว่าพวกเขาต้องการลดระดับการเขียนคอมไพเลอร์ที่เป็นไปตามมาตรฐานอย่างสมบูรณ์: VLA เป็นสัตว์ที่ค่อนข้างยากที่จะนำไปใช้และโค้ดจำนวนมากสามารถทำได้โดยไม่ต้องใช้ดังนั้นจึงเหมาะสมสำหรับคอมไพเลอร์ใหม่ในบางตัวใหม่ แพลตฟอร์มที่ไม่ต้องใช้ VLA ทันที
อาจจะ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 ( ลิงค์ )
รหัสระดับมาตรฐานเป็นที่นี่ ;
ฉันไม่รู้มากเกี่ยวกับการเปรียบเทียบ ... รหัสของฉันอาจมีข้อบกพร่อง
long test_arr_without_init() { return ARR_SIZE; }
void test_arr_without_init() {}
ตอนนี้ได้ คุณต้องกระโดดผ่านห่วงเพื่อให้แน่ใจว่ารหัสที่คุณกำลังวัดเป็นรหัสที่คุณต้องการวัด
std::array
std::array
จะมีประสิทธิภาพน้อยกว่าอาร์เรย์ C อย่างไร
at()
ก็ไม่ได้อยู่ในเช่นเดียวกับoperator[]
std::vector
ไม่มีการลดประสิทธิภาพหรือขยายโค้ดไปstd::array
คอมไพเลอร์ได้รับการออกแบบมาเพื่อเพิ่มประสิทธิภาพของสิ่งนี้ และแน่นอนว่าการเพิ่มฟังก์ชันที่ตรวจสอบแล้วเป็นเครื่องมือดีบักที่ยอดเยี่ยมและมีข้อได้เปรียบมากมาย @Lou Franco: รหัส C ++ ทั้งหมดอาจขึ้นอยู่กับไลบรารีมาตรฐาน - นั่นคือสิ่งที่มันมีไว้สำหรับ @Earlz: หากคุณไม่มี STL แสดงว่าไม่ใช่ C ++ และนั่นคือจุดสิ้นสุดของสิ่งนั้น
std::array
เพื่อให้มีขนาดใหญ่กว่าการใช้งานอาร์เรย์ C ที่เทียบเท่ากัน