Bagaimana cara menggunakan kembali ostringstream?

Jawaban:

156

Saya telah menggunakan urutan clear dan str di masa lalu:

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

Yang telah melakukan hal untuk arus string input dan output. Atau, Anda dapat menghapus secara manual, lalu mencari urutan yang sesuai untuk memulai:

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

Itu akan mencegah beberapa realokasi dilakukan strdengan menimpa apa pun yang ada di buffer keluaran saat ini. Hasilnya seperti ini:

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

Jika Anda ingin menggunakan string untuk fungsi-c, Anda dapat menggunakan std::ends, meletakkan penghentian null seperti ini:

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

std::endsadalah relik dari deprecated std::strstream, yang bisa menulis langsung ke array karakter yang Anda alokasikan di stack. Anda harus memasukkan null terminating secara manual. Namun, std::endstidak usang, saya rasa karena masih berguna seperti kasus di atas.

Johannes Schaub - litb
sumber
Saya mencoba menggunakan s.str () dengan ostream. Ukurannya mengacaukannya (saya dapat melihat karakter pertama adalah null tetapi mencetak lebih banyak). Apakah ada cara yang baik untuk memperbaiki panjang str? saya menggunakan s.str (). c_str (); ATM dan bekerja dengan baik
Sebenarnya ini pun tidak benar. Saya baru saja melakukannya s.str("");. auto str = s.str(); auto cstr = str.c_str(); file << cstr; s.clear(); s.seekp(0); s << ends;
std :: ending tidak berfungsi untuk saya dalam pengujian 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>" dan jika saya menggunakan kembali dengan string panjang yang berbeda saya mendapatkan bit yang tersisa
David van Laatum
Alternatif adalah jawaban yang benar jika Anda ingin menghindari realokasi. Dan jika Anda ingin benar-benar "memulai baru" tanpa realokasi, cukup panggil seekp (0) lagi setelah mengirim std :: end. s.seekp(0); s << std::ends; s.seekp(0);
Chip Grandits
5

Tampaknya ostr.str("")panggilan itu berhasil.

Diego Sevilla
sumber
9
Perlu diperhatikan bahwa ini tidak akan menggunakan kembali buffer yang mendasari dari ostringstream - ini hanya menetapkan buffer baru. Jadi saat Anda menggunakan kembali objek ostringstream, Anda masih mengalokasikan dua buffer. Saya tidak berpikir ostringstream dirancang untuk digunakan kembali seperti yang Anda inginkan.
razlebe
2
Itu juga tidak menghapus status, yang dilakukan .clear (). Saya setuju, ini tidak dimaksudkan untuk digunakan seperti ini. Buat saja yang baru untuk memastikan. Hanya jika profil Anda, Anda akan mengetahui apakah itu membuat perbedaan.
Brian Neal
1
sgreeve, Brian, itu benar. Perhatikan, bagaimanapun, bagaimana metode litb di atas membutuhkan penggunaan std :: berakhir. Ini menggunakan kembali buffer, tetapi membuat Anda membuat kode berbeda seperti biasa dengan stringstream (biasanya Anda tidak menggunakan std :: end).
Diego Sevilla
2

Jika Anda akan menghapus buffer dengan cara yang akan membuatnya dihapus sebelum digunakan pertama kali, Anda harus menambahkan sesuatu ke buffer terlebih dahulu dengan 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
    }
};
Unkle George
sumber
Saya tidak melihat perilaku gagal di VS2012. Selanjutnya, menyebut clearakan menyebabkan yang failbitmenjadi set jika sungai kosong. Sementara hanya menelepon seekpseharusnya hanya kembali jika tidak ada aliran.
Jonathan Mee
0

Kamu tidak. Gunakan dua aliran dengan nama berbeda untuk kejelasan dan biarkan kompiler pengoptimal mengetahui bahwa ia dapat menggunakan kembali yang lama.

Sebastian Ganslandt
sumber
4
Pertimbangkan kasus penggunaan di mana kode tersebut mengulang data input, menulis ke sebuah ostringstream(berdasarkan data yang dibaca) dan kemudian harus menulis string yang dibangun di ostringstreamsuatu tempat dari waktu ke waktu (misalnya setelah urutan karakter tertentu dibaca) dan mulai membangun string baru.
Andre Holzner