我可以通过 0 拷贝获取 std::stringstream 累积数据的原始指针吗?

问题描述 投票:0回答:1

这就是我想做的:

std::stringstream s;
s<<"Some "<<std::hex<<123<<" hex data"<<...;

有了这个

s
,我非常想把它传递出去,这是很容易做到的。但是,在某些时候,需要(概念上)将其传递到仅接受描述内存区域的
const void */size_t
对的接口。

据我所知(希望得到纠正),在 C++17 及以下版本中没有办法使用 0 拷贝来做到这一点。必须使用

.str()
这将创建一个字符串副本,然后从那里获取它。

作为一个“黑客”,这就是我想出的:

struct stringstream_extractor_t {
    // this structure will be used to get access to pbase member function which is protected
    // the way we do that is to inherit from it
    template <typename T>
    struct accessor_t : public T {
        static const char* data(const accessor_t* pT) { return pT->pbase(); }
    };

    // get the return type for std::stringstream::rdbuf
    using bufferType = std::remove_pointer<decltype(((std::stringstream*)nullptr)->rdbuf())>::type;

    // having the std::stringstream::rdbuf result type, we can now create our accessor type
    // which will be able to call pbase inside it
    using accessorType = accessor_t<bufferType>;

    // this is where we deposit the data, in a const manner
    const std::string_view _data;

    // syntactic sugar: init the _data with the stuff from stream reference
    stringstream_extractor_t(std::stringstream& stream) : _data{getBuffer(stream), static_cast<size_t>(stream.tellp())} {}

    // syntactic sugar: init the _data with the stuff from stream pointer
    stringstream_extractor_t(std::stringstream* pStream) :
        _data{pStream ? getBuffer(*pStream) : nullptr, pStream ? static_cast<size_t>(pStream->tellp()) : 0} {}

    // this uses the accessor type to grab access to data
    static const char* getBuffer(const std::stringstream& stream) {
        // we get the buffer and we cast it to our accessor type. This is safe, as we do not
        // have any members inside it, just a static function
        const accessorType* pBuffer = reinterpret_cast<accessorType*>(stream.rdbuf());

        // grab the data now
        return accessorType::data(pBuffer);
    }

    // convenience functionality
    inline const char* data() const { return _data.data(); }
    inline size_t size() const { return _data.size(); }
};

这是它的使用方式,具有类似 C 的界面

std::stringstream s;
s << "Hi there! " << std::hex << 0xdeadbeef;

const stringstream_extractor_t e(s);
write(2, e.data(), e.size());

是的,我知道指针必须保持活动状态(std::stringstream 实例),以及所有生命周期的影响。

是否有一种更舒适的非复杂方法来实现这个非常基本的事情:使用移动语义从输出字符串流中获取缓冲区。

我显然错过了一些东西,这不应该这么难。

https://godbolt.org/z/G53P6oocb

c++ stringstream
1个回答
4
投票

在 C++ 20 中你可以这样做

#include <iostream>
#include <ios>
#include <sstream>


void c_style_func(const char* cp, std::size_t size) {
    std::cout << std::string_view  (cp,size) << "\n";
}

int main() {
    std::stringstream s;
    s << "Hi there! " << std::hex << 0xdeadbeef;
    auto view = s.view();
    c_style_func(view.data(), view.size());
}

使用标准 1411 的第 29.8.2.4 页

basic_string_view view() const noexcept; 11 令 sv 为 basic_string_view。 12 返回: 一个 sv 对象,引用 buf 中 basic_stringbuf 的底层字符序列: (12.1) — 如果 ios_base::out 设置为 mode,则返回 sv(pbase(), high_mark-pbase())。 (12.2) — 否则,如果 ios_base::in 设置为 mode,则返回 sv(eback(), egptr()-eback())。 (12.3) — 否则,返回 sv()。 13 [注意:在底层字符序列被破坏或失效后使用返回的 sv 对象 *这是未定义的行为,除非 sv.empty() 为 true。 ——尾注]


2024 年补充:

std::string_view.data

 相比,
std::string::data
不受保证,并且通常 不是 null 终止。因此,上面的用法仍然安全,因为它不假设 NTS,但是请注意,如果您使用任何通常只采用
char*
的函数。

© www.soinside.com 2019 - 2024. All rights reserved.