วิธีการนำ ostringstream กลับมาใช้ใหม่


117

ฉันต้องการล้างข้อมูลและนำ ostringstream กลับมาใช้ใหม่ (และบัฟเฟอร์พื้นฐาน) เพื่อที่แอปของฉันจะได้ไม่ต้องทำการจัดสรรให้มากนัก ฉันจะรีเซ็ตวัตถุเป็นสถานะเริ่มต้นได้อย่างไร


คำตอบ:


156

ฉันเคยใช้ลำดับความชัดเจนและความแข็งแกร่งในอดีต:

// clear, because eof or other bits may be still set. 
s.clear();
s.str("");

ซึ่งได้ทำสิ่งนี้สำหรับสตริงสตรีมทั้งอินพุตและเอาต์พุต หรือคุณสามารถล้างด้วยตนเองจากนั้นค้นหาลำดับที่เหมาะสมเพื่อเริ่มต้น:

s.clear();
s.seekp(0); // for outputs: seek put ptr to start
s.seekg(0); // for inputs: seek get ptr to start

ซึ่งจะป้องกันไม่ให้มีการจัดสรรstrซ้ำโดยการเขียนทับสิ่งที่อยู่ในบัฟเฟอร์เอาต์พุตในปัจจุบันแทน ผลลัพธ์เป็นดังนี้:

std::ostringstream s;
s << "hello";
s.seekp(0);
s << "b";
assert(s.str() == "bello");

หากคุณต้องการใช้สตริงสำหรับฟังก์ชัน c คุณสามารถใช้ได้โดยstd::endsใส่ค่าว่างในการยกเลิกดังนี้:

std::ostringstream s;
s << "hello";
s.seekp(0);
s << "b" << std::ends;
assert(s.str().size() == 5 && std::strlen(s.str().data()) == 1);

std::endsเป็นความสัมพันธ์ของการเลิกใช้งานstd::strstreamซึ่งสามารถเขียนโดยตรงไปยังอาร์เรย์ถ่านที่คุณจัดสรรไว้บนสแต็ก คุณต้องแทรกโมฆะการยุติด้วยตนเอง อย่างไรก็ตามstd::endsไม่ได้เลิกใช้งานฉันคิดว่าเพราะมันยังมีประโยชน์เหมือนในกรณีข้างต้น


ฉันพยายามใช้ s.str () กับ ostream ขนาดทำให้ยุ่งเหยิง (ฉันเห็นว่าอักขระตัวแรกเป็นโมฆะ แต่มันพิมพ์ออกมาได้มากกว่านี้) มีวิธีที่ดีในการแก้ไขความยาวของ str หรือไม่? ฉันใช้ s.str (). c_str (); ATM และใช้งานได้ดี

อันที่จริงแม้จะไม่ถูกต้อง ฉันแค่ทำs.str("");แทน auto str = s.str(); auto cstr = str.c_str(); file << cstr; s.clear(); s.seekp(0); s << ends;

std :: end ใช้ไม่ได้สำหรับฉันในการทดสอบของ Google boost::any a = 1; std::ostringstream buffer; buffer << a << std::ends; EXPECT_EQ( buffer.str(), "any<(int)1>" ); TestUtilsTest.cpp:27: Failure Expected: buffer.str() Which is: "any<(int)1>\0" To be equal to: "any<(int)1>" และถ้าฉันใช้ซ้ำกับสตริงที่มีความยาวต่างกันฉันจะเหลือบิต
David van Laatum

ทางเลือกคือคำตอบที่แท้จริงหากคุณต้องการหลีกเลี่ยงการจัดสรรใหม่ และหากคุณต้องการ "เริ่มต้นใหม่" อย่างแท้จริงโดยไม่ต้องจัดสรรใหม่ให้โทรหา findp (0) อีกครั้งหลังจากส่ง std :: end s.seekp(0); s << std::ends; s.seekp(0);
Chip Grandits

5

ดูเหมือนว่าการostr.str("")โทรจะหลอกลวง


9
ควรค่าแก่การชี้ให้เห็นว่าสิ่งนี้จะไม่ใช้บัฟเฟอร์พื้นฐานซ้ำจาก ostringstream เพียงแค่กำหนดบัฟเฟอร์ใหม่ ดังนั้นในขณะที่คุณใช้อ็อบเจกต์ ostringstream ซ้ำคุณยังคงจัดสรรบัฟเฟอร์สองตัว ฉันไม่คิดว่า ostringstream ได้รับการออกแบบมาเพื่อใช้ซ้ำในลักษณะที่คุณต้องการ
razlebe

2
นอกจากนี้ยังไม่ชัดเจนสถานะซึ่งเป็นสิ่งที่. clear () ทำ ฉันเห็นด้วยจริงๆแล้วมันไม่ได้มีไว้ให้ใช้แบบนี้ แค่สร้างใหม่ให้ชัวร์ เฉพาะในกรณีที่โปรไฟล์ของคุณคุณจะพบว่ามันสร้างความแตกต่างหรือไม่
Brian Neal

1
sgreeve, Brian ถูกต้อง อย่างไรก็ตามโปรดทราบว่าวิธีการของ litb ข้างต้นต้องการการใช้ std :: สิ้นสุดอย่างไร มันใช้บัฟเฟอร์ซ้ำ แต่ทำให้โค้ดของคุณแตกต่างไปจากเดิมตามปกติกับสตริงสตรีม (โดยปกติคุณไม่ได้ใช้ std :: end)
Diego Sevilla

2

หากคุณกำลังจะล้างบัฟเฟอร์ด้วยวิธีที่จะทำให้ถูกล้างก่อนที่จะใช้งานครั้งแรกคุณจะต้องเพิ่มบางอย่างลงในบัฟเฟอร์ก่อนด้วย MSVC

struct Foo {
    std::ostringstream d_str;
    Foo() { 
        d_str << std::ends;   // Add this
    }
    void StrFunc(const char *);
    template<class T>
    inline void StrIt(const T &value) {
        d_str.clear();
        d_str.seekp(0);  // Or else you'll get an error with this seek
        d_str << value << std::ends;
        StrFunc(d_str.str().c_str());  // And your string will be empty
    }
};

ฉันไม่เห็นพฤติกรรมที่ล้มเหลวใน VS2012 นอกจากนี้โทรclearจะทำให้เกิดfailbitจะเป็นชุดถ้ากระแสที่ยังว่างอยู่ ในขณะที่โทรเพียงแค่seekpควรกลับมาหากไม่มีสตรีม
Jonathan Mee

0

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


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