ใน C ++ จุดของ std :: array คืออะไรถ้าต้องกำหนดขนาด ณ เวลารวบรวม?

2020-02-15 c++ c++11 stdarray

ให้อภัยความไม่รู้ของฉันดูเหมือนว่า std::array หมายถึงการแทนที่ STL สำหรับอาร์เรย์ปกติของคุณ แต่เนื่องจากขนาดอาร์เรย์ต้องถูกส่งผ่านเป็นพารามิเตอร์เทมเพลตจึงป้องกันเราจากการสร้าง std::array ด้วยขนาดที่รู้จักกันเฉพาะตอนรันไทม์

std::array<char,3> nums {1,2,3}; // Works.

constexpr size_t size = 3;
std::array<char,size> nums {1,2,3}; // Works.

const buf_size = GetSize();
std::array<char, buf_size> nums; // Doesn't work.

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

วิธีแก้ปัญหาที่ฉันใช้สำหรับสิ่งนี้คือ:

// Create a array pointer for on-the-spot usecases like reading from a file.
char *data = new char[size];
...
delete[] data;

หรือ:

// Use unique_ptr as a class member and I don't want to manage the memory myself.
std::unique_ptr<char[]> myarr_ = std::unique_ptr<char[]>(new char[size]);

ถ้าฉันไม่สนใจขนาดคงที่ฉันรู้ว่าฉันสามารถใช้ std::vector<char> ด้วยขนาดที่กำหนดไว้ล่วงหน้าดังนี้:

std::vector<char> my_buf (buf_size);

เหตุใดผู้ออกแบบ std::array เลือกที่จะไม่สนใจกรณีการใช้งานนี้ บางทีฉันไม่เข้าใจ usecase ที่แท้จริงสำหรับ std::array

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

Answers

std::array คือการแทนที่สำหรับอาร์เรย์สไตล์ C

มาตรฐาน C ++ ไม่อนุญาตให้มีการประกาศอาร์เรย์สไตล์ C โดยไม่มีขนาดที่กำหนดเวลาคอมไพล์

ความง่ายในการเขียนโปรแกรม

std::array ช่วยให้อินเทอร์เฟซที่เป็นประโยชน์และสำนวนต่าง ๆ ที่ใช้ใน std::vector ด้วยอาร์เรย์แบบ C ปกติอย่างใดอย่างหนึ่งไม่สามารถมี .size() (ไม่ sizeof สับ) .at() (ยกเว้นสำหรับออกจากช่วง) front()/back() , iterators, อื่น ๆ ทุกอย่างต้องเขียนด้วยมือ

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

สองเหตุผลหลักที่ฉันเข้าใจคือ:

  • std::array ใช้อินเทอร์เฟซของ STL สำหรับประเภทคอลเลกชันซึ่งอนุญาตให้ std::array ถูกส่งผ่านตามที่เป็นไปยังฟังก์ชันและวิธีการที่ยอมรับ STL iterator ใด ๆ
  • เพื่อป้องกันการสลายตัวชี้อาร์เรย์ ... (ด้านล่าง)

... นี่คือการเก็บรักษาข้อมูลประเภทข้ามขอบเขตของฟังก์ชัน / เมธอดเนื่องจากมันจะป้องกัน Array Pointer Decay

รับอาร์เรย์ C / C ++ เปล่าคุณสามารถส่งไปยังฟังก์ชันอื่นเป็นอาร์กิวเมนต์พารามิเตอร์ได้ 4 วิธี:

void by_value1   ( const T* array )
void by_value2   ( const T array[] )
void by_pointer  ( const T (*array)[U] )
void by_reference( const T (&array)[U] )
  • by_value1 และ by_value2 มีทั้งความหมายเหมือนกันและทำให้เกิดการสลายตัวชี้เพราะฟังก์ชั่นที่ได้รับไม่ทราบ sizeof อาร์เรย์
  • by_pointer และ by_reference ทั้งกำหนดว่า U โดยเป็นที่รู้จักกันอย่างต่อเนื่องรวบรวมเวลา แต่รักษา sizeof ข้อมูล

ดังนั้นหากคุณหลีกเลี่ยงการสลายตัวของอาเรย์โดยใช้ by_pointer หรือ by_reference ตอนนี้คุณมีปัญหาการบำรุงรักษาทุกครั้งที่คุณเปลี่ยนขนาดของอาเรย์ที่คุณต้องอัปเดตไซต์ไซต์ทั้งหมดที่มีขนาดนั้นใน U ด้วยตนเอง

โดยใช้ std::array มันได้รับการดูแลสำหรับคุณโดยการทำให้ฟังก์ชั่นเหล่านั้น template ฟังก์ชั่นที่ U เป็นพารามิเตอร์ (รับคุณยังสามารถใช้ by_pointer และ by_reference เทคนิค แต่ด้วยไวยากรณ์ Messier)

... ดังนั้น std::array เพิ่มวิธีที่ 5 :

template<typename T, size_t N>
void by_stdarray( const std::array<T,N>& array )

Related