简体   繁体   中英

Passing raw data in C++

Up until now, whenever I wanted to pass some raw data to a function (like a function that loads an image from a buffer), I would do something like this:

void Image::load(const char* buffer, std::size_t size);

Today I took a look at the Boost libraries, more specifically at the property_tree/xml_parser.hpp header, and I noticed this function signature:

 template<typename Ptree> 
 void read_xml(std::basic_istream<typename Ptree::key_type::value_type>&, 
               Ptree &, int = 0);

This actually made me curious: is this the correct way to pass around raw data in C++, by using streams? Or am I misinterpreting what the function is supposed to be used for?

If it's the former, could you please point me to some resource where I can learn how to use streams for this? I haven't found much myself (mainly API references), and I have't been able to find the Boost source code for the XML parser either.


Edit: Some extra details

Seems there's been some confusion as to what I want. Given a data buffer, how can I convert it to a stream such that it is compatible with the read_xml function I posted above? Here's my specific use case:

I'm using the SevenZip C library to read an XML file from an archive. The library will provide me with a buffer and its size, and I want to put that in stream format such that it is compatible with read_xml . How can I do that?

Well, streams are quite used in C++ because of their conveniences:
- error handling
- they abstract away the data source, so whether you are reading from a file, an audio source, a camera, they are all treated as input streams
- and probably more advantages I don't know of

Here is an overview of the IOstream library, perhaps that might better help you understand what's going on with streams: http://www.cplusplus.com/reference/iostream/

Understanding what they are exactly will help you understand how and when to use them.

There's no single correct way to pass around data buffers. A combination of pointer and length is the most basic way; it's C-friendly. Passing a stream might allow for sequential/chunked processing - ie not storing the whole file in memory at the same time. If you want to pass a mutable buffer (that might potentially grow), a vector<char>& would be a good choice.

Specifically on Windows, a HGLOBAL or a section object handle might be used.

The C++ philosophy explicitly allows for many different styles, depending on context and environment. Get used to it.

Buffers of raw memory in C++ can either be of type unsigned char* , or you can create a std::vector<unsigned char> . You typically don't want to use just a char* for your buffer since char is not guaranteed by the standard to use all the bits in a single byte (ie, this will end up varying by platform/compiler). That being said, streams have some excellent uses as well, considering that you can use a stream to read bytes from a file or some other input, etc., and from there, store that data in a buffer.

Seems there's been some confusion as to what I want. Given a data buffer, how can I convert it to a stream such that it is compatible with the read_xml function I posted above?

Easily (I hope PTree::Key_type::value_type would be something like char ):

istringstream stream(string(data, len));
read_xml(stream, ...);

More on string streams here .

This is essentially using a reference to pass the stream contents. So behind the scene's it's essentially rather similar to what you did so far and it's essentially the same - just using a different notation. Simplified, the reference just hides the pointer aspect, so in your boost example you're essentially working with a pointer to the stream.

References got the advantage avoiding all the referencing/dereferencing and are therefore easier to handle in most situations. However they don't allow you multiple levels of (de-)referencing.

The following two example functions do essentially the same:

void change_a(int &var, myclass &cls)
{
    var = cls.convert();
}

void change_b(int *var, myclass *cls)
{
    *var = cls->convert();
}

Talking about the passed data itself: It really depends on what you're trying to achieve and what's more effective. If you'd like to modify a string, utilizing an object of class std::string might be more convenient than using a classic pointer to a buffer ( char * ). Streams got the advantage that they can represent several different things (eg data stream on the network, a compressed stream or simply a file or memory stream). This way you can write single functions or methods that accept a stream as input and will instantly work without worrying about the actual stream source. Doing this with classic buffers can be more complicated. On the other side you shouldn't forget that all objects will add some overhead, so depending on the job to be done a simple pointer to a character string might be perfectly fine (and the most effective solution). There's no "the one way to do it".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM