ด้านล่างบรรทัด: ด้วยการจัดการพื้นที่สีขาวที่เหมาะสมต่อไปนี้เป็นวิธีการeof
ใช้ (และแม้กระทั่งเชื่อถือได้มากกว่าfail()
สำหรับการตรวจสอบข้อผิดพลาด):
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
( ขอบคุณ Tony D สำหรับคำแนะนำเพื่อเน้นคำตอบดูความคิดเห็นของเขาด้านล่างเพื่อดูว่าทำไมสิ่งนี้ถึงมีประสิทธิภาพมากกว่านี้ )
ข้อโต้แย้งหลักต่อการใช้eof()
ดูเหมือนจะไม่มีความละเอียดอ่อนที่สำคัญเกี่ยวกับบทบาทของพื้นที่สีขาว ข้อเสนอของฉันคือการตรวจสอบeof()
อย่างชัดเจนไม่เพียง แต่ไม่ " ผิดเสมอไป " - ซึ่งดูเหมือนว่าจะเป็นความคิดเห็นที่สำคัญในหัวข้อนี้และหัวข้อ SO ที่คล้ายกัน - แต่ด้วยการจัดการพื้นที่สีขาวที่เหมาะสม การจัดการข้อผิดพลาดและเป็นวิธีการแก้ไขที่ถูกต้องเสมอ (แม้ว่าไม่จำเป็นต้องเข้มงวดที่สุด)
เพื่อสรุปสิ่งที่ถูกแนะนำว่าเป็นการสิ้นสุด "เหมาะสม" และลำดับการอ่านมีดังต่อไปนี้:
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
ความล้มเหลวเนื่องจากความพยายามในการอ่านเกินกว่า eof ถือเป็นเงื่อนไขการเลิกจ้าง นี่หมายความว่าไม่มีวิธีง่ายๆในการแยกแยะระหว่างสตรีมที่ประสบความสำเร็จและสตรีมที่ประสบความสำเร็จด้วยเหตุผลอื่นนอกเหนือจาก eof ใช้สตรีมต่อไปนี้:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
ยุติกับชุดfailbit
สำหรับทุกสามการป้อนข้อมูล ในครั้งแรกและครั้งที่สามeofbit
ก็มีการตั้งค่า ดังนั้นในอดีตลูปจึงต้องการตรรกะพิเศษที่น่าเกลียดมาก ๆ เพื่อแยกอินพุตที่เหมาะสม (ที่ 1) จากอันที่ไม่เหมาะสม (ที่ 2 และที่ 3)
ในขณะที่ทำสิ่งต่อไปนี้:
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
ที่นี่in.fail()
ตรวจสอบว่าตราบใดที่มีบางสิ่งที่จะอ่านมันเป็นสิ่งที่ถูกต้อง มันมีจุดประสงค์ไม่ได้เป็นเพียง terminator ในขณะที่วง
จนถึงตอนนี้ดีมาก แต่เกิดอะไรขึ้นถ้ามีช่องว่างต่อท้ายในสตรีม - สิ่งที่ฟังดูเป็นข้อกังวลที่สำคัญeof()
ในฐานะเทอร์มิเนเตอร์
เราไม่จำเป็นต้องยอมจำนนการจัดการข้อผิดพลาดของเรา; แค่กินพื้นที่สีขาว:
while( !in.eof() )
{
int data;
in >> data >> ws; // eat whitespace with std::ws
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
std::ws
ข้ามที่อาจเกิดขึ้น (ศูนย์หรือมากกว่า) พื้นที่ต่อท้ายในกระแสในขณะที่การตั้งค่าeofbit
และไม่ได้เป็น failbit
ดังนั้นin.fail()
ทำงานได้ตามที่คาดหวังตราบใดที่มีข้อมูลอย่างน้อยหนึ่งที่จะอ่าน หากกระแสทั้งหมดที่ว่างเปล่ายังเป็นที่ยอมรับรูปแบบที่ถูกต้องคือ:
while( !(in>>ws).eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
/* this will never fire if the eof is reached cleanly */
// now use data
}
สรุป:การสร้างอย่างถูกต้องwhile(!eof)
ไม่เพียง แต่เป็นไปได้และไม่ผิดเท่านั้น แต่ยังช่วยให้ข้อมูลสามารถแปลได้ภายในขอบเขตและให้การแยกการตรวจสอบข้อผิดพลาดที่ชัดเจนจากธุรกิจตามปกติ ที่ถูกกล่าวว่าwhile(!fail)
อาจเป็นสำนวนที่พบบ่อยและสั้นและอาจเป็นที่ต้องการในสถานการณ์ (ข้อมูลเดียวต่อประเภทการอ่าน) ที่เรียบง่าย
scanf(...) != EOF
จะไม่ทำงานใน C เนื่องจากscanf
คืนค่าจำนวนฟิลด์ที่แยกวิเคราะห์และกำหนดสำเร็จแล้ว เงื่อนไขที่ถูกต้องคือscanf(...) < n
ตำแหน่งที่n
มีจำนวนฟิลด์ในสตริงรูปแบบ