Подтвердить что ты не робот

Как я могу получить длину буфера const string без копирования или поиска?

У меня есть const std::stringstream и желание узнать, сколько байтов содержится в его базовом буфере строк.

  • Я не могу seekg до конца, tellg, а затем seekg вернуться к началу, потому что ни одна из этих операций не доступна const ly.

  • Я не хочу получать str().size(), потому что str() возвращает копию, и это может быть не тривиальное количество данных.

Есть ли у меня хорошие варианты?


(Сам поток представлен мне как const, только потому, что он является членом другого типа, и я получаю ссылку const на объект этого типа. Поток представляет содержимое "документа" ", его инкапсулирующий объект представляет собой ответ CGI, и я пытаюсь создать точную строку заголовка Content-Length HTTP из operator<<(std::ostream&, const cgi_response&).)

4b9b3361

Ответ 1

Мне никогда не нравилось потоковое буферирование, но это работает для меня:

#include <iostream>
#include <sstream>

std::stringstream::pos_type size_of_stream(const std::stringstream& ss)
{
    std::streambuf* buf = ss.rdbuf();

    // Get the current position so we can restore it later
    std::stringstream::pos_type original = buf->pubseekoff(0, ss.cur, ss.out);

    // Seek to end and get the position
    std::stringstream::pos_type end = buf->pubseekoff(0, ss.end, ss.out);

    // Restore the position
    buf->pubseekpos(original, ss.out);

    return end;
}

int main()
{
    std::stringstream ss;

    ss << "Hello";
    ss << ' ';
    ss << "World";
    ss << 42;

    std::cout << size_of_stream(ss) << std::endl;

    // Make sure the output string is still the same
    ss << "\nnew line";
    std::cout << ss.str() << std::endl;

    std::string str;
    ss >> str;
    std::cout << str << std::endl;
}

Ключ состоит в том, что rdbuf() есть const, но возвращает неконстантный буфер, который затем можно использовать для поиска.

Ответ 2

Если вы хотите узнать оставшийся доступный размер ввода:

#include <iostream>
#include <sstream>

std::size_t input_available(const std::stringstream& s)
{
    std::streambuf* buf = s.rdbuf();
    std::streampos pos = buf->pubseekoff(0, std::ios_base::cur, std::ios_base::in);
    std::streampos end = buf->pubseekoff(0, std::ios_base::end, std::ios_base::in);
    buf->pubseekpos(pos, std::ios_base::in);
    return end - pos;
}

int main()
{
    std::stringstream stream;

    // Output
    std::cout << input_available(stream) << std::endl; // 0
    stream << "123 ";
    std::cout << input_available(stream) << std::endl; // 4
    stream << "567";
    std::cout << input_available(stream) << std::endl; // 7

    // Input
    std::string s;
    stream >> s;
    std::cout << input_available(stream) << std::endl; // 4
    stream >> s;
    std::cout << input_available(stream) << std::endl; // 0
}

Это похоже на решение @Cornstalks, но правильно позиционирует входную последовательность.

Ответ 3

Это должно работать:))

#include <iostream>
#include <sstream>
#include <boost/move/move.hpp>

int main()
{
    const std::stringstream ss("hello");
    std::cout << boost::move(ss).str().size();
}