4

My compiler (C++Builder6) syntactically allows array member initialization (at least with zero), but actually it doesn't really do it. So the assert in the example given below fails depending from the context.

#include <assert.h>

struct TT {
    char b[8];
    TT(): b() {}
};

void testIt() {
    TT t;
    assert(t.b[7] == 0);
}

Changing the compiler isn't an option at the moment. My question is: what will be the best way to "repair" this flaw with respect to future portability and standard conformance?


Edit: As it turns out, my first example was too short. It missed the point, that the fill level of the array is so essential, that it has to be stored very close to the array, which is: in the same class.

Even if the original problem remains, my actual problem pattern is usually this:

struct TT2 {
    int size;
    char data[8];
    // ... some more elements
    TT2(): size(0), data() {}
    // ... some more methods
};
Wolf
  • 9,679
  • 7
  • 62
  • 108
  • 1
    http://qc.embarcadero.com/wc/qcmain.aspx?d=83751 shows this is fixed in newer versions (XE onwards), and shows a workaround using [`boost::value_initialized`](http://www.boost.org/doc/libs/1_54_0/libs/utility/value_init.htm) –  Nov 11 '13 at 11:56
  • @hvd: I think suggesting `boost::value_initialized` would be a good regular answer. Sure, it's somewhat heavy in the source, but since the work is restricted to the declaration, it seems to me the best option so far. – Wolf Nov 11 '13 at 12:46
  • Sure. I'll do so when I can test to verify what actually works and what doesn't, but that won't be for some hours. –  Nov 11 '13 at 13:27
  • Actually, I can't get C++Builder 6 to even compile this. It doesn't accept the `: b()` syntax, complaining "Call to function 'b' without prototype". –  Nov 11 '13 at 20:16
  • @hvd: Thanks for your effort. I have applied [BCB6 patch4](http://edn.embarcadero.com/article/29793), maybe this matters? `bcc32 --version` says `Borland C++ 5.6.4 für Win32 Copyright (c) 1993, 2002 Borland` at my installation. – Wolf Nov 12 '13 at 13:10

3 Answers3

4

I think you may use this:

TT() { std::fill(b, b + 8, char()); }

This way you will solve your problem while nothing is wrong with portability and standard conformance!

BigBoss
  • 6,904
  • 2
  • 23
  • 38
  • As long as the compiler respects the value-initialisation of `char()`. An explicit `0` might be safer. – Mike Seymour Nov 11 '13 at 12:23
  • @MikeSeymour Question talk about standard and future conformance, value-initialization is part of standard, so I think `char()` is more standard than int literal `0`! – BigBoss Nov 20 '13 at 08:52
  • The question is about a compiler that *doesn't* conform to the standard; specifically, one in which value-initialisation is broken. In that case, I'd avoid value-initialisation altogether, even if I do observe that it works in this case. – Mike Seymour Nov 20 '13 at 11:52
  • It's not possible to avoid value initialisation when you have const or reference members, and **BCB6 lacks only array member initialisation**. I've so much code that depends so heavily on proper initialisation of simple members (using ctr syntax) that I'm absolutely sure about this. – Wolf Nov 23 '13 at 15:50
3

You may use fill_n like suggested in: C/C++ initialization of a normal array with one default value

If no fill_n is available, you can always use memset like:

TT() {memset(b, 0, sizeof b);}
Community
  • 1
  • 1
jcm
  • 2,568
  • 14
  • 18
  • As in [BigBoss's std::fill example](http://stackoverflow.com/a/19905764/2932052), I don't like duplicating the size literal. – Wolf Nov 11 '13 at 12:19
  • 1
    @WolfP. If you don't want to duplicate the size literal, you can get array's size by: (sizeof b / sizeof b[0]); – jcm Nov 11 '13 at 12:32
  • Yes, that's NELEMS ;) ...now you see the duplication potential for each member. It's really **horrible**, that and how long the error existed in BCB. – Wolf Nov 11 '13 at 12:38
  • @WolfP. Well, I suppose that standard c++11 way is not an option as you're working with C++Builder6, so I would suggest to use a template to get array's size: `template size_t arsize( T (&ar)[N] ) {return N;}` then, you should be able to use `memset(b,0,arsize(b));` – jcm Nov 11 '13 at 13:03
  • An interesting article about getting number of element in an array: http://blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx – jcm Nov 11 '13 at 13:45
  • Interesting read :) ...but in the sense of the opening question, I'd prefer a template solution for **it** than for only a **part of it** – Wolf Nov 11 '13 at 14:10
  • @WolfP. I'm sorry but I don't fully understand what do you mean with "only a part of it". If what you want is a template that inits to 0 all elements from a received array, you can modify previous code to: `template size_t initarray( T (&ar)[N] ) { memset(array, 0, N*sizeof(T)); }`. But, most probably, I'm misinterpreting something. – jcm Nov 11 '13 at 21:08
  • I'd prefer to restrict changes to the declaration point, maybe using a sort of `template class Array { /*...*/ };` Then there would be no need for explicit initialization in ctr blocks (I have to handle more than one class). Since `size` is given, I can calculate the size of the array by `(sizeof (T) * size)` or use `size` directly as in BigBoss's answer - and I do it only **once**: in the template definition. BTW: your current size definition `(sizeof b / sizeof b[0])` isn't the correct number of bytes for [memset](http://www.cplusplus.com/reference/cstring/memset/). – Wolf Nov 12 '13 at 14:34
  • You're right about number of bytes for memset, actually, `sizeof b` should be enough. I just updated it this way by mistake because we were discussing about number of elements in the array. On the other hand, my initial proposal already used size directly but you complained about duplicating size literal, this is why I proposed a way to automatically obtain number of elements in the array. Nerveless, if creating an Array template is valid for you, you can extend previous proposal to achieve it. – jcm Nov 12 '13 at 17:00
1

I would like to append previous posts that if you are using a character array as a string then it is enough to write in the constructor

TT() { b[0] = '\0'; }

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Yes, that's true, but choosing `char` in my example was maybe a mistake; strings are already implemented using `AnsiString` or `std::string`. – Wolf Nov 11 '13 at 12:05