0

I need to store bits in files and std::bitset would be perfect for this, because I need many of its operations when I read the structure back again. The class seems to consist of just an array of the bits and no other member data.

So instead of this

BYTE minuteOfDay[(60 * 24 / CHAR_BIT) + ((60 * 24 % CHAR_BIT) ? 1 : 0)];

I could have this:

std::bitset<60 * 24> minuteOfDay;

If the class should change with a future Visual Studio release and I need to read files written with an old version, I guess I could still just copy the old <bitset> header into my project.

But just before making a really stupid decision: Is this idea somehow flawed for a reason I don't foresee right now?

Felix Dombek
  • 13,664
  • 17
  • 79
  • 131
  • So, to be clear, you don't care if it's supposed to work or guaranteed to work, you just care if it happens to work? If so, why not just test? – David Schwartz Apr 13 '16 at 17:41
  • You'll still need to store and read the [underlying type](http://en.cppreference.com/w/cpp/utility/bitset/to_ullong) , such this is the smallest unit you can use. – πάντα ῥεῖ Apr 13 '16 at 17:42
  • I am testing it and it looks fine. @πάνταῥεῖ what do you mean? – Felix Dombek Apr 13 '16 at 17:51
  • What, your undefined behaviour appeared to work? Well _that_ never lulled anyone into a false sense of security and came back to bite them later! – Useless Apr 13 '16 at 17:59

2 Answers2

1

Is this idea somehow flawed ...?

Yes.

Firstly, the failure modes: as you guessed, std::bitset might alter its internal representation. Aside from that, it's anyway not (guaranteed to be) a standard layout type, so the initial write is ill-defined. Aside from that, how would you read it back in? Presumably just read into a correctly-aligned buffer and type-pun it? That's illegal too.

Secondly, the proposed fix: copying your old <bitset> header along is horrible. It won't be part of the actual standard library, and will still inject itself illegally into namespace std. It's entirely possible some other code will use the native std::bitset and lead to horrible errors.

On top of that, it may simply not work when divorced from its native version of your standard lib.

Thirdly, correct solutions: either

  1. (de)serialize it to some well-defined format, using the public interface of std::bitset

    note that this is pretty trivial anyway: std::bitset::to_string already exists, and you can re-construct an instance from that string

  2. or write a replacement class which is controlled by you and guaranteed to be trivially serializable. Just because you don't get std::bitset for free doesn't mean you have to bang rocks together use a raw char array.
Useless
  • 64,155
  • 6
  • 88
  • 132
0

I understand that by writing it to file you mean taking an address of the std::bitset variable and writing the raw bytes? In this case the answer is NO. This process is called entity-serialization or entity-encoding, and you can not entity-serialize std::bitset (or any class containing it as a member field), since std::bitset is not standard-layout type.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Well, at least with gcc and clang `std::bitset` [is standard layout](http://coliru.stacked-crooked.com/a/931a854f36867094) so it's more correct to say it's *not guaranteed* to be standard layout. Also `struct S { int* ptr; };` is standard-layout, but you don't want to entity-serialize it as well. – Anton Savin Apr 13 '16 at 17:58
  • @AntonSavin, first point is actually the same to me. Once Standard is invoked, not guaranteed and is not is of similar weight. On the second part, it is incorrect semantically, but it least it is going to produce well defined results if you serialize/deserialize it in the same program. Non-standard layout types do not have this trait. – SergeyA Apr 13 '16 at 18:11