tags:

views:

118

answers:

3

I've read about POD objects in C++. I wanna have a POD struct to be written into a file. So it should have only public data with no ctors/dtors etc. But as far as i know it can have static function in it. So can I use "named constructor idiom" here? I need dynamic initialization, but I don't want to duplicate arguments checking at every struct initialization Here is a simple example (it's just simple example, not a working code):

struct A
{
  int day;
  int mouth;
  int year;

   static A MakeA(const int day, const int month, const int year)
   {  
      // some simple arguments chech
      if ( !(day >= 1 && day <= 31) || !(month >=1 && month <=12) || !(year <= 2010) )
         throw std::exception();

      A result;
      result.day = day;
      result.month = month;
      result.year = year;
      return result;
   }
};

So I have some kind of a constructor and a POD structure that I can simply fwrite to a file? It it correct?

+3  A: 

That should be fine.

You can even have a non-static member functions (as long as they are not virtual)

You cannot have something that is called automatically (like ctor/dtor). Thingsthat you explicitly call are fine.

James Curran
I would suggest that you can have a constructor or destructor. I am not sure of the problem.
Clifford
@Clifford we are evaluating this in a strict formal sense. In practice, having a constructor won't harm. You will still be able to use `memcpy` on it. But in a formal sense, when you do that you are not guaranteed that when you load it back you get the same value again.
Johannes Schaub - litb
@Clifford: depends whether you're writing to the standard or the implementation. Under the current standard, a class with a constructor is non-POD, so if you want the POD guarantee that a byte-for-byte copy is a valid object, then you can't have a constructor. With most (all?) current implementations you're quite right: the mere existence of a constructor won't actually cause any problems with the validity of a byte-for-byte copy of an object. Obviously there are things a constructor could do (like storing `this`) that would cause problems, but they're easily avoided.
Steve Jessop
@Steve, @Johannes: Thanks; I stand corrected/educated. In all cases I think I'd suggest serialisation/deserialsation member functions in any case, even when otherwise a POD. Then the class can take care of its file representation in an appropriate manner, and won't cause any surprises under maintenance as it might if the class becomes non-POD, but the serialisation were separate and not modified to suit.
Clifford
+1  A: 

If you write the stream operators it makes life a lot simpler.
Its not as if writing in binary is significantly faster (as you need to write the code to convert for different endian formats) and space nowadays is practically irrelevant.

struct A
{
  int day;
  int mouth;
  int year;

   A(const int day, const int month, const int year)
   {  
      // some simple arguments chech
      if ( !(day >= 1 && day <= 31) || !(month >=1 && month <=12) || !(year <= 2010) )
         throw std::exception();

      this->day    = day;
      this->month  = month;
      this->year   = year;
   }
};
std::ostream& operator<<(std::ostream& str, A const& data)
{
    return str << data.day << " " << data.month << " " << data.year << " ";
}
std::istream& operator>>(std::istream& str,A& data)
{
    return str >> data.day >> data.month >> data.year;
}

With this defined the whole plethera of standard algorithms becomes available and easy to use.

int main()
{
    std::vector<A>    allDates;
    // Fill allDates with some dates.

    // copy dates from a file:
    std::ifstream  history("plop");
    std::copy(std::istream_iterator<A>(history),
              std::istream_iterator<A>(),
              std::back_inserter(allDates)
             );

    // Now  save a set of dates to a file:
    std::ofstream  history("plop2");
    std::copy(allDates.begin(),
              allDates.end(),
              std::ostream_iterator<A>(history)
             );
}
Martin York
I would like to see a speed comparison of something that has to do ASCII conversions vs. a few simple byte swaps. I bet that ASCII data is still significantly slower.
Omnifarious
In fact, it is: http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking and while space may be incredibly cheap, network and disk IO bandwidth isn't.
Omnifarious
@Omnifarious: In which case you'd use platform agnostic algorithms to pack data up, and then safely unpack it on the other side. Pointing out a possible deficiency in a localized area doesn't mean you can generalize and say "therefore it's too slow." Keep problems in their domain; I seriously doubt there's any reason to worry about performance here. (Which follows the same old guideline: correctness over performance. It's easy to make correct code faster, and *it works*.)
GMan
@Omnifarious: I doubt it is significant (it will be slower). But the difference in speed will be overshadow by other much more expensive operations (like disk/network latency) that for any real application you will not notice.
Martin York
@Omnifarious: This argument has already been played out a lost in real life. Disk Bandwidth is a read hearing. But I agree that network bandwidth may play a role in your discussion. But it is easy to add a compression layer onto of your stream (thus decoupling the application from the actual compression used and allowing greater flexibility in the long wrong. Using a binary format is basically tightly coupling you to the compression format (because it is in the application layer)).
Martin York
@Martin - For the record, I did not downvote you. Your answer is a good answer, even if I don't really agree with it.
Omnifarious
@Martin York: I have a question. Suppose the POD struct undergoes a revision and new members are added. Is there a way in which the developer gets automatically reminded to update the overloaded insertion and extraction operators?
Chubsdad
@chubsdad: No. But are you trying to suggest that a binary version would not require changes!
Martin York
+1  A: 

You are correct. That's just an ordinary old piece of data. No funny virtual table pointers or anything like that in it.

Now, I'm still not sure it's all that good an idea to simply use fwrite to write the data to a file. You can do that and fread the data back in provided that the program that does the fread is written with the same version of the compiler used to do the fwrite in the first place. But if you switch compilers, platforms, or sometimes even versions, that may change.

I would suggest something like Protocol Buffers to do the work of making your data structure persistent.

Omnifarious