Structure layout

K

kelvSYC

As you might know, std::fwrite only works on POD classes (or in the
very least, I am advised to use this only on POD classes...). I have
this POD class that I want to add methods, and thus have to replace
parts of my code where I have to call std::fwrite.

For example, I have

struct foo {
int a;
char b;
};

// ...
foo f;
FILE* file;
std::fwrite (&f, 1, sizeof(f), file);
// ...

If I add a method to foo, how would I change the code snippet?
 
I

Ian

kelvSYC said:
As you might know, std::fwrite only works on POD classes (or in the
very least, I am advised to use this only on POD classes...). I have
this POD class that I want to add methods, and thus have to replace
parts of my code where I have to call std::fwrite.

For example, I have

struct foo {
int a;
char b;
};

// ...
foo f;
FILE* file;
std::fwrite (&f, 1, sizeof(f), file);
// ...

If I add a method to foo, how would I change the code snippet?
As long as there are no virtual methods or non pod members, it should
still work. But I'd give it proper streaming operators.

friend std::eek:stream& operator<<( std::eek:stream& out, const foo& f );
friend std::istream& operator>>( std::istream& out, foo& f );

Ian
 
R

Rapscallion

Ian said:
....
As long as there are no virtual methods or non pod members, it should
still work. But I'd give it proper streaming operators.

friend std::eek:stream& operator<<( std::eek:stream& out, const foo& f );

.... which probably isn't quite the same as
fwrite (&f, sizeof(f), 1, file);
 
D

davidrubin

If you're going to define streaming operators for 'foo', there is no
reason not to include non-pod members. I'm certain there is code
available to stream STL containers (otherwise you can write it). And if
you have your own value-semantic types, you should always provide
streaming operators for them. /david
 
K

kelvSYC

Ian said:
As long as there are no virtual methods or non pod members, it should
still work.

I see. Adding a nonvirtual member function would not affect its
pod-ness.

So what would I do if I had something like

struct bar {
int a;
char b[32];
};

and I wanted to add a constructor/non-pod member/virtual member
function/etc. to make it non-pod? How would I change the code snippet
above?
But I'd give it proper streaming operators.

friend std::eek:stream& operator<<( std::eek:stream& out, const foo& f );
friend std::istream& operator>>( std::istream& out, foo& f );

I thought streaming operators were meant for text input and output
only. std::fwrite is binary output.
 
D

davidrubin

kelvSYC said:
Ian said:
As long as there are no virtual methods or non pod members, it should
still work.

I see. Adding a nonvirtual member function would not affect its
pod-ness.

So what would I do if I had something like

struct bar {
int a;
char b[32];
};

and I wanted to add a constructor/non-pod member/virtual member
function/etc. to make it non-pod? How would I change the code snippet
above?

For example,

struct bar {
int a;
char b[32];

std::vector<int> v;

private:
// not implemented
bar(const bar&);
bar& operator=(const bar&);

public:
bar() : a(0) { b[0] = 0; }
~bar();

virtual std::eek:stream& streamOut(std::eek:stream& stream);
};

But I would not advise this. Make it a proper class.
I thought streaming operators were meant for text input and output
only. std::fwrite is binary output.

No. There is no reason why the istream cannot represent a binary
stream. Indeed, it all depends on how the underlying streambuf is
implemented. It is easy to imagine something like

my_FwriteStreamBuf buf("filename"); // implemented with 'fwrite'
std::eek:stream stream(&buf);
stream << object << std::endl;

/david
 
P

Peter Julian

kelvSYC said:
As long as there are no virtual methods or non pod members, it should
still work.

I see. Adding a nonvirtual member function would not affect its
pod-ness.

So what would I do if I had something like

struct bar {
int a;
char b[32];
};

and I wanted to add a constructor/non-pod member/virtual member
function/etc. to make it non-pod? How would I change the code snippet
above?
But I'd give it proper streaming operators.

friend std::eek:stream& operator<<( std::eek:stream& out, const foo& f );
friend std::istream& operator>>( std::istream& out, foo& f );

I thought streaming operators were meant for text input and output
only. std::fwrite is binary output.

No sir, those operators are binary.

As far as a non-pod class is concerned, why not develop a Bar class and a
container to serialize the data. A std::string is implemented instead of a
fixed char array:

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <iterator>
#include <stdexcept>

class Bar
{
int m_n;
std::string m_s;
public:
Bar(int n, std::string s) : m_n(n), m_s(s) { }
~Bar() { }

friend std::eek:stream& operator<<( std::eek:stream& os, const Bar& r_bar_ )
{
os << r_bar_.m_n << " ";;
os << r_bar_.m_s;
return os;
}

friend std::istream& operator>>( std::istream& is, Bar& r_bar )
{
is >> r_bar.m_n >> r_bar.m_s;
return is;
}
}; // class Bar

class BarContainer
{
std::string s_filename;
std::vector<Bar> v_bar;
public:
BarContainer(std::string s) : v_bar(), s_filename(s) { }
~BarContainer() { }

// member functions
void push_back(const Bar& r_bar_)
{
v_bar.push_back(r_bar_);
}

void write() const
{
std::eek:fstream ofs;
ofs.open(s_filename.c_str());
if (!ofs)
{
throw std::exception("while opening file for output");
}

std::eek:stream& os = ofs;
std::copy( v_bar.begin(),
v_bar.end(),
std::eek:stream_iterator<Bar>(os, "\n") );
ofs.close();
std::cout << "\nBarContainer::write() ... file ";
std::cout << s_filename << " created successfully.\n";
} // write()

void display() const
{
std::cout << "BarContainer::display() [ size = ";
std::cout << v_bar.size() << " ]\n";

std::eek:stream& r_os = std::cout;
std::copy( v_bar.begin(),
v_bar.end(),
std::eek:stream_iterator<Bar>(r_os, "\n") );
/*
// the above code is simpler than...
typedef std::vector<Bar>::iterator VITER;
VITER viter = v_bar.begin();
for (viter; viter != v_bar.end(); ++viter)
{
std::cout << *viter << "\n";
}
*/
} // display()

}; // class Bar

int main()
{
// initialize Container with filename
BarContainer bc("data.dat");

// load Container
bc.push_back(Bar(0, "string_zero"));
bc.push_back(Bar(1, "string_one"));
bc.push_back(Bar(2, "string_two"));
bc.push_back(Bar(3, "string_three"));
bc.push_back(Bar(4, "string_four"));

// display its contents
bc.display();

try
{
// serialize Container to file
bc.write();
}
catch (const std::exception& e)
{
std::cerr << "Error !\n";
std::cerr << e.what() << "\n";
}

return 0;
} // main(...)

/*
BarContainer::display() [ size = 5 ]
0 string_zero
1 string_one
2 string_two
3 string_three
4 string_four

BarContainer::write() ... file data.dat created successfully.

*/
 
K

kelvSYC

But I'd give it proper streaming operators.
No. There is no reason why the istream cannot represent a binary
stream. Indeed, it all depends on how the underlying streambuf is
implemented. It is easy to imagine something like

my_FwriteStreamBuf buf("filename"); // implemented with 'fwrite'
std::eek:stream stream(&buf);
stream << object << std::endl;

Since I'm not of good enough ability to write a streambuf that would be
implemented with fwrite (I don't fully understand what I have to do in
order to write one), where could I find one?
 
D

davidrubin

kelvSYC said:
Since I'm not of good enough ability to write a streambuf that would be
implemented with fwrite (I don't fully understand what I have to do in
order to write one), where could I find one?

You can use 'std::fstream'. Construct or 'open' an 'std::fstream'
object with the 'ios_base::binary' open mode. /david
 
K

kelvSYC

You can use 'std::fstream'. Construct or 'open' an 'std::fstream'
object with the 'ios_base::binary' open mode. /david

I'm actually looking for binary (ie. not character-based) output, so,
seeing how everyone advises not to (ab)use write() for unformatted
output, I'd need to find a stream(buf) that would do this.
 
D

davidrubin

kelvSYC said:
I'm actually looking for binary (ie. not character-based) output, so,
seeing how everyone advises not to (ab)use write() for unformatted
output, I'd need to find a stream(buf) that would do this.

Maybe I'm not understanding you. You either want something like this:

my_Pod pod;
//...
std::fstream ofs(filename, ios_base::binary);
ofs.write((const char *)&my_pod, sizeof pod);

or this (to show use of std::streambuf)

my_Pod pod;
//...
std::fstream ofs(filename, ios_base::binary);
std::streambuf *buf = ofs.rdbuf();
buf->sputn((const char *)&pod, sizeof pod);
buf->pubsync();

or this

std::eek:stream& operator<<(std::eek:stream& stream, const my_Pod& pod)
{
// one of the above implementations, probably the first
return stream;
}

/david
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,297
Messages
2,571,530
Members
48,251
Latest member
Amelia8778

Latest Threads

Top