Zero-size array as struct member

Discussion in 'C++' started by thomas, Aug 18, 2010.

  1. thomas

    thomas Guest

    Hi, I need your help.

    ----------
    struct SvrList{
    unsigned int uNum;
    GameSvr svr[0]; //line A
    };
    ---------

    Once I declared a struct like this to store server list info.
    It's supposed to be used like this.

    ----------
    SvrList* pList = (SvrList*)malloc(sizeof(
    SvrList) + svrNum*sizeof(GameSvr));
    pList->uNum, pList->svr[0], pList->svr[1].... blabla..
    ---------

    The vs2005 compiler gives me the "nonstandard extension used : zero-
    sized array in struct/union" warning though.

    I may keep my eye closed to the warning since everything looks fine.
    But I don't know whether anything bad may happen to me some day due to
    running environment changes(porting to different platforms, or any
    other conditions).

    One work-around way is to declare a one-sized array as struct member,
    but I didn't see any substantial changes except no warning in this
    case.

    Any body give some suggestions?
    thomas, Aug 18, 2010
    #1
    1. Advertising

  2. El 18/08/2010 13:30, thomas escribió:
    > Hi, I need your help.
    >
    > ----------
    > struct SvrList{
    > unsigned int uNum;
    > GameSvr svr[0]; //line A
    > };
    > ---------
    >
    > Once I declared a struct like this to store server list info.
    > It's supposed to be used like this.
    >
    > ----------
    > SvrList* pList = (SvrList*)malloc(sizeof(
    > SvrList) + svrNum*sizeof(GameSvr));
    > pList->uNum, pList->svr[0], pList->svr[1].... blabla..
    > ---------
    >
    > The vs2005 compiler gives me the "nonstandard extension used : zero-
    > sized array in struct/union" warning though.
    >
    > I may keep my eye closed to the warning since everything looks fine.
    > But I don't know whether anything bad may happen to me some day due to
    > running environment changes(porting to different platforms, or any
    > other conditions).
    >
    > One work-around way is to declare a one-sized array as struct member,
    > but I didn't see any substantial changes except no warning in this
    > case.
    >
    > Any body give some suggestions?


    You can change to

    struct SvrList{
    unsigned int uNum;
    GameSvr *svr; //line A
    };

    and still use array indexes.
    Julián Rodríguez Bajo, Aug 18, 2010
    #2
    1. Advertising

  3. thomas

    thomas Guest

    On Aug 18, 7:33 pm, Julián Rodríguez Bajo <> wrote:
    > El 18/08/2010 13:30, thomas escribió:
    >
    >
    >
    > > Hi, I need your help.

    >
    > > ----------
    > > struct SvrList{
    > >      unsigned int uNum;
    > >      GameSvr  svr[0];            //line A
    > > };
    > > ---------

    >
    > > Once I declared a struct like this to store server list info.
    > > It's supposed to be used like this.

    >
    > > ----------
    > > SvrList* pList = (SvrList*)malloc(sizeof(
    > > SvrList) + svrNum*sizeof(GameSvr));
    > > pList->uNum, pList->svr[0], pList->svr[1].... blabla..
    > > ---------

    >
    > > The vs2005 compiler gives me the "nonstandard extension used : zero-
    > > sized array in struct/union" warning though.

    >
    > > I may keep my eye closed to the warning since everything looks fine.
    > > But I don't know whether anything bad may happen to me some day due to
    > > running environment changes(porting to different platforms, or any
    > > other conditions).

    >
    > > One work-around way is to declare a one-sized array as struct member,
    > > but I didn't see any substantial changes except no warning in this
    > > case.

    >
    > > Any body give some suggestions?

    >
    > You can change to
    >
    > struct SvrList{
    >       unsigned int uNum;
    >       GameSvr  *svr;            //line A
    >
    > };
    >
    > and still use array indexes.


    Thanks, that works.
    But I will call "new" two times: one to allocate memory for struct
    SvrList, one for "*svr".

    I really want to know whether there's any side effect if I use zero-
    sized member.
    thomas, Aug 18, 2010
    #3
  4. thomas wrote:
    > Hi, I need your help.
    >
    > ----------
    > struct SvrList{
    > unsigned int uNum;
    > GameSvr svr[0]; //line A
    > };
    > ---------
    >
    > Once I declared a struct like this to store server list info.
    > It's supposed to be used like this.
    >
    > ----------
    > SvrList* pList = (SvrList*)malloc(sizeof(
    > SvrList) + svrNum*sizeof(GameSvr));
    > pList->uNum, pList->svr[0], pList->svr[1].... blabla..


    I wouldn't call this fine. Even
    pList->svr[0]
    is accessing the element that is out of array's bounds, and that is UB.
    How come your program is not crashing, or at least going crazy? Maybe
    you are just unlucky to have a bug hidden.

    > ---------
    >
    > The vs2005 compiler gives me the "nonstandard extension used : zero-
    > sized array in struct/union" warning though.
    >
    > I may keep my eye closed to the warning since everything looks fine.
    > But I don't know whether anything bad may happen to me some day due to
    > running environment changes(porting to different platforms, or any
    > other conditions).
    >
    > One work-around way is to declare a one-sized array as struct member,
    > but I didn't see any substantial changes except no warning in this
    > case.
    >
    > Any body give some suggestions?
    Vladimir Jovic, Aug 18, 2010
    #4
  5. thomas

    Jeff Flinn Guest

    Vladimir Jovic wrote:
    > thomas wrote:
    >> Hi, I need your help.
    >>
    >> ----------
    >> struct SvrList{
    >> unsigned int uNum;
    >> GameSvr svr[0]; //line A
    >> };
    >> ---------
    >>
    >> Once I declared a struct like this to store server list info.
    >> It's supposed to be used like this.
    >>
    >> ----------
    >> SvrList* pList = (SvrList*)malloc(sizeof(
    >> SvrList) + svrNum*sizeof(GameSvr));
    >> pList->uNum, pList->svr[0], pList->svr[1].... blabla..

    >
    > I wouldn't call this fine. Even
    > pList->svr[0]
    > is accessing the element that is out of array's bounds, and that is UB.
    > How come your program is not crashing, or at least going crazy? Maybe
    > you are just unlucky to have a bug hidden.


    It's an old C programmers hack. I've come across this idiom in lot's old
    C code, particularly driver and os code. Microsoft Win32 is rife with it.

    Jeff
    Jeff Flinn, Aug 18, 2010
    #5
  6. Vladimir Jovic <> wrote:
    > thomas wrote:
    >> Hi, I need your help.
    >>
    >> ----------
    >> struct SvrList{
    >> unsigned int uNum;
    >> GameSvr svr[0]; //line A
    >> };
    >> ---------
    >>
    >> Once I declared a struct like this to store server list info.
    >> It's supposed to be used like this.
    >>
    >> ----------
    >> SvrList* pList = (SvrList*)malloc(sizeof(
    >> SvrList) + svrNum*sizeof(GameSvr));
    >> pList->uNum, pList->svr[0], pList->svr[1].... blabla..

    >
    > I wouldn't call this fine. Even
    > pList->svr[0]
    > is accessing the element that is out of array's bounds, and that is UB.
    > How come your program is not crashing, or at least going crazy?


    pList->svr[0] is accessing memory allocated by the malloc() call,
    hence it can't crash (well, at least if 'GameSvr' is a POD type).
    Juha Nieminen, Aug 18, 2010
    #6
  7. Fred Zwarts <> wrote:
    > You can use std::vector. A vector can have 0 or more elements.
    > It also removes the need for malloc and free.


    And also makes the struct something like 10 times slower to allocate
    and deallocate, as well as consuming more memory.
    Juha Nieminen, Aug 18, 2010
    #7
  8. Juha Nieminen wrote:
    > Vladimir Jovic <> wrote:
    >> thomas wrote:
    >>> Hi, I need your help.
    >>>
    >>> ----------
    >>> struct SvrList{
    >>> unsigned int uNum;
    >>> GameSvr svr[0]; //line A
    >>> };
    >>> ---------
    >>>
    >>> Once I declared a struct like this to store server list info.
    >>> It's supposed to be used like this.
    >>>
    >>> ----------
    >>> SvrList* pList = (SvrList*)malloc(sizeof(
    >>> SvrList) + svrNum*sizeof(GameSvr));
    >>> pList->uNum, pList->svr[0], pList->svr[1].... blabla..

    >> I wouldn't call this fine. Even
    >> pList->svr[0]
    >> is accessing the element that is out of array's bounds, and that is UB.
    >> How come your program is not crashing, or at least going crazy?

    >
    > pList->svr[0] is accessing memory allocated by the malloc() call,
    > hence it can't crash (well, at least if 'GameSvr' is a POD type).


    If the array's size is zero, how can you access even one element?
    The example similar to the original example, except this one compiles :

    #include <iostream>
    using namespace std;
    struct A
    {
    int a;
    int b[0];
    };
    int main()
    {
    A *p = new A;

    p->a = 5;
    p->b[0] = 6;
    p->b[1] = 7;
    p->b[2] = 8;

    std::cout << "p->a="<<p->a << std::endl
    << "p->b[0]="<<p->b[0] << std::endl
    << "p->b[1]="<<p->b[1] << std::endl
    << "p->b[2]="<<p->b[2] << std::endl;

    delete( p );
    }



    And the output :

    ../a.out
    p->a=5

    p->b[0]=6

    p->b[1]=7

    p->b[2]=8
    *** glibc detected *** ./a.out: free(): invalid next size (fast):
    0x087b8008 ***
    ======= Backtrace: =========
    /lib/libc.so.6[0x260874]
    /lib/libc.so.6(cfree+0x96)[0x2628d6]
    /usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0x1ba461]
    ../a.out(__gxx_personality_v0+0x24a)[0x8048886]
    /lib/libc.so.6(__libc_start_main+0xe6)[0x2095d6]
    ../a.out(__gxx_personality_v0+0x35)[0x8048671]
    ======= Memory map: ========
    00101000-001e8000 r-xp 00000000 fd:07 442834
    /usr/lib/libstdc++.so.6.0.10
    001e8000-001ec000 r--p 000e6000 fd:07 442834
    /usr/lib/libstdc++.so.6.0.10
    001ec000-001ee000 rw-p 000ea000 fd:07 442834
    /usr/lib/libstdc++.so.6.0.10
    001ee000-001f3000 rw-p 001ee000 00:00 0
    001f3000-00356000 r-xp 00000000 fd:00 58475 /lib/libc-2.8.so
    00356000-00358000 r--p 00163000 fd:00 58475 /lib/libc-2.8.so
    00358000-00359000 rw-p 00165000 fd:00 58475 /lib/libc-2.8.so
    00359000-0035c000 rw-p 00359000 00:00 0
    00821000-0083d000 r-xp 00000000 fd:00 58474 /lib/ld-2.8.so
    0083d000-0083e000 r--p 0001c000 fd:00 58474 /lib/ld-2.8.so
    0083e000-0083f000 rw-p 0001d000 fd:00 58474 /lib/ld-2.8.so
    00848000-00849000 r-xp 00848000 00:00 0 [vdso]
    009ac000-009d3000 r-xp 00000000 fd:00 58481 /lib/libm-2.8.so
    009d3000-009d4000 r--p 00026000 fd:00 58481 /lib/libm-2.8.so
    009d4000-009d5000 rw-p 00027000 fd:00 58481 /lib/libm-2.8.so
    00db3000-00dc0000 r-xp 00000000 fd:00 58490
    /lib/libgcc_s-4.3.0-20080428.so.1
    00dc0000-00dc1000 rw-p 0000c000 fd:00 58490
    /lib/libgcc_s-4.3.0-20080428.so.1
    08048000-08049000 r-xp 00000000 fd:09 4555963
    /sandbox/vladimir/data_create/a.out
    08049000-0804a000 rw-p 00000000 fd:09 4555963
    /sandbox/vladimir/data_create/a.out
    087b8000-087d9000 rw-p 087b8000 00:00 0 [heap]
    b7f00000-b7f21000 rw-p b7f00000 00:00 0
    b7f21000-b8000000 ---p b7f21000 00:00 0
    b80a5000-b80a8000 rw-p b80a5000 00:00 0
    b80c7000-b80c8000 rw-p b80c7000 00:00 0
    bfe96000-bfeab000 rw-p bffeb000 00:00 0 [stack]
    Aborted
    Vladimir Jovic, Aug 18, 2010
    #8
  9. thomas

    Bo Persson Guest

    Juha Nieminen wrote:
    > Fred Zwarts <> wrote:
    >> You can use std::vector. A vector can have 0 or more elements.
    >> It also removes the need for malloc and free.

    >
    > And also makes the struct something like 10 times slower to
    > allocate and deallocate, as well as consuming more memory.


    Yes, but you get rid of the SvrList (which keeps size and buffer) if
    you let the std::vector do the job. You don't have to dynamically
    allocate the vector itself.


    Bo Persson
    Bo Persson, Aug 18, 2010
    #9
  10. thomas

    Joe Greer Guest

    Vladimir Jovic <> wrote in news:i4gueb$vqv$1
    @news.albasani.net:

    >
    > If the array's size is zero, how can you access even one element?


    What's your point? Why would you do that? If b were a vector, you would
    get similar behavior. That is, it is just as undefined if you don't
    bother to check the size of the vector before assigning data. This is a
    idiom used by device drivers to return information requiring a minimum
    number of allocations and a minimum number of frees. It is always used
    with malloc and the size of the array is always embedded in the struct
    somewhere so that you don't go out of bounds. So, to fix up your code
    below.

    > The example similar to the original example, except this one compiles :
    >
    > #include <iostream>
    > using namespace std;
    > struct A
    > {
    > int a;

    int b_len;
    > int b[0];
    > };


    A * AFactory(int sz)
    {
    A * p = (A *)malloc(sizeof(A) + sz * sizeof(b[0]));
    p->b_len = sz;
    return p
    }

    > int main()
    > {
    > A *p = new A;

    A *p = AFactory(0);

    >
    > p->a = 5;


    // We know we didn't allocate space so we wouldn't bother with
    this, but...
    if (p->b_len >= 3)
    {
    > p->b[0] = 6;
    > p->b[1] = 7;
    > p->b[2] = 8;

    }
    >
    > std::cout << "p->a="<<p->a << std::endl;

    for (int ix = 0; ix < p->b_len; ++ix)
    std::cout << "p->b[" << ix << "] = " << p->b[ix] << std::endl;
    >

    free(p); // you could also have function for this, but
    deallocation doesn't require additional info.

    > }
    >
    >


    I would never advocate the above as a C++ application pattern, but if you
    are messing in drivers and kernel, then every clock cycle counts and
    multiple heap hits can kill performance.

    This is one of the places I would really like to see some sort of VLA
    available (at least if it allocated memory in this fashion). The nice
    thing is that it is one heap allocation and free. Rolling your own as
    above is a bit of a pain. Fortunately, I haven't had to do stuff like
    that in years.

    joe
    Joe Greer, Aug 18, 2010
    #10
  11. thomas wrote:
    > Hi, I need your help.
    >
    > ----------
    > struct SvrList{
    > unsigned int uNum;
    > GameSvr svr[0]; //line A
    > };
    > ---------
    >
    > Once I declared a struct like this to store server list info.
    > It's supposed to be used like this.
    >
    > ----------
    > SvrList* pList = (SvrList*)malloc(sizeof(
    > SvrList) + svrNum*sizeof(GameSvr));
    > pList->uNum, pList->svr[0], pList->svr[1].... blabla..
    > ---------
    >
    > The vs2005 compiler gives me the "nonstandard extension used : zero-
    > sized array in struct/union" warning though.
    > ...
    > One work-around way is to declare a one-sized array as struct member,
    > but I didn't see any substantial changes except no warning in this
    > case.


    Well, declaring a 1-sized array is the way it is normally done. The
    memory allocation is supposed to be done as follows

    SvrList* pList = (SvrList*) malloc(offsetof(SvrList, svr) +
    svrNum * sizeof(GameSvr));

    As you can notice, you can declare the array with any non-zero size in
    this case, since the above total size calculation approach is not
    affected by the declared array size.

    --
    Best regards,
    Andrey Tarasevich
    Andrey Tarasevich, Aug 18, 2010
    #11
  12. Joe Greer wrote:
    > Vladimir Jovic <> wrote in news:i4gueb$vqv$1
    > @news.albasani.net:
    >
    >> If the array's size is zero, how can you access even one element?

    >
    > What's your point? Why would you do that? If b were a vector, you would
    > get similar behavior. That is, it is just as undefined if you don't
    > bother to check the size of the vector before assigning data. This is a


    Will next assertion pass or fail :
    int a[0];
    assert( sizeof( a ) == 0 );
    ?
    What bothers me is how can you use an array of size zero.

    > idiom used by device drivers to return information requiring a minimum
    > number of allocations and a minimum number of frees. It is always used
    > with malloc and the size of the array is always embedded in the struct
    > somewhere so that you don't go out of bounds. So, to fix up your code
    > below.
    >
    >> The example similar to the original example, except this one compiles :
    >>
    >> #include <iostream>
    >> using namespace std;
    >> struct A
    >> {
    >> int a;

    > int b_len;
    >> int b[0];
    >> };

    >
    > A * AFactory(int sz)
    > {
    > A * p = (A *)malloc(sizeof(A) + sz * sizeof(b[0]));
    > p->b_len = sz;
    > return p
    > }


    This looks like a hack. Why declare an array of size 0? Why not use a
    pointer (like someone suggested)? Is it another (now obsolete and
    depreciated) way of declaring pointers?
    Vladimir Jovic, Aug 19, 2010
    #12
  13. thomas

    James Kanze Guest

    On Aug 18, 1:36 pm, Jeff Flinn <> wrote:
    > Vladimir Jovic wrote:
    > > thomas wrote:
    > >> Hi, I need your help.


    > >> ----------
    > >> struct SvrList{
    > >> unsigned int uNum;
    > >> GameSvr svr[0]; //line A
    > >> };
    > >> ---------


    > >> Once I declared a struct like this to store server list info.
    > >> It's supposed to be used like this.


    > >> ----------
    > >> SvrList* pList = (SvrList*)malloc(sizeof(
    > >> SvrList) + svrNum*sizeof(GameSvr));
    > >> pList->uNum, pList->svr[0], pList->svr[1].... blabla..


    > > I wouldn't call this fine. Even
    > > pList->svr[0]
    > > is accessing the element that is out of array's bounds, and
    > > that is UB. How come your program is not crashing, or at
    > > least going crazy? Maybe you are just unlucky to have a bug
    > > hidden.


    > It's an old C programmers hack. I've come across this idiom in
    > lot's old C code, particularly driver and os code. Microsoft
    > Win32 is rife with it.


    Except that it's not legal C, either. The C language was
    carefully specified so that a bounds checking implementation
    would be legal, and the above will fail in such cases.

    In C++, of course, the declaration he's looking for is
    std::vector<SvrList>, without any manual new.

    --
    James Kanze
    James Kanze, Aug 19, 2010
    #13
  14. On Aug 19, 11:50 am, Vladimir Jovic <> wrote:
    > Joe Greer wrote:
    > > Vladimir Jovic <> wrote in news:i4gueb$vqv$1
    > > @news.albasani.net:

    >
    > >> If the array's size is zero, how can you access even one element?

    >
    > > What's your point?  Why would you do that?  If b were a vector, you would
    > > get similar behavior.  That is, it is just as undefined if you don't
    > > bother to check the size of the vector before assigning data. This is a

    >
    > Will next assertion pass or fail :
    >         int a[0];
    >         assert( sizeof( a ) == 0 );
    > ?


    That snippet should not compile, because it is not allowed to define
    objects with size 0.

    > What bothers me is how can you use an array of size zero.


    You can't, except as a non-standard predecessor of the 'flexible array
    member' of C99.
    Some compilers will allow a zero-sized array as the last member of a
    structure as a way to let the structure contain an array of
    unspecified size. It is the full responsibility of the programmer to
    ensure enough space gets allocated or the number of array members that
    is actually needed.

    <snip>
    >
    > > A * AFactory(int sz)
    > > {
    > >    A * p = (A *)malloc(sizeof(A) + sz * sizeof(b[0]));
    > >    p->b_len = sz;
    > >    return p
    > > }

    >
    > This looks like a hack. Why declare an array of size 0? Why not use a
    > pointer (like someone suggested)? Is it another (now obsolete and
    > depreciated) way of declaring pointers?


    It is a hack, and it is commonly known as the 'struct hack'.
    The reasons for not using a pointer can be very diverse.
    In the (C-)code that I am currently working with, this hack is used in
    the definition of the messages that are passed between different parts
    of the system.
    As the system consists of multiple (embedded) processors, it is a
    requirement that a message is always fully contained within a single
    contiguous buffer, so that it can be easily transported to a different
    processor. This also rules out the use of internal pointers within the
    buffer.

    Bart v Ingen Schenau
    Bart van Ingen Schenau, Aug 19, 2010
    #14
  15. thomas

    James Kanze Guest

    On Aug 18, 3:30 pm, Juha Nieminen <> wrote:
    > Vladimir Jovic <> wrote:
    > > thomas wrote:
    > >> Hi, I need your help.


    > >> ----------
    > >> struct SvrList{
    > >> unsigned int uNum;
    > >> GameSvr svr[0]; //line A
    > >> };
    > >> ---------


    > >> Once I declared a struct like this to store server list info.
    > >> It's supposed to be used like this.


    > >> ----------
    > >> SvrList* pList = (SvrList*)malloc(sizeof(
    > >> SvrList) + svrNum*sizeof(GameSvr));
    > >> pList->uNum, pList->svr[0], pList->svr[1].... blabla..


    > > I wouldn't call this fine. Even
    > > pList->svr[0]
    > > is accessing the element that is out of array's bounds, and
    > > that is UB. How come your program is not crashing, or at
    > > least going crazy?


    > pList->svr[0] is accessing memory allocated by the malloc()
    > call, hence it can't crash (well, at least if 'GameSvr' is
    > a POD type).


    pList->svr[0] is accessing beyond the end of the array, hence,
    the code is undefined behavior, both in C and in C++. The
    C language has been carefully specified to allow bounds checking
    implementations---there has been (and maybe still is) one.

    In C99, flexible array members were introduced to support this
    idiom. In C++, std::vector does the job a lot cleaner.

    --
    James Kanze
    James Kanze, Aug 19, 2010
    #15
  16. thomas

    Jeff Flinn Guest

    James Kanze wrote:
    > On Aug 18, 1:36 pm, Jeff Flinn <> wrote:
    >> Vladimir Jovic wrote:
    >>> thomas wrote:
    >>>> Hi, I need your help.

    >
    >>>> ----------
    >>>> struct SvrList{
    >>>> unsigned int uNum;
    >>>> GameSvr svr[0]; //line A
    >>>> };
    >>>> ---------

    >
    >>>> Once I declared a struct like this to store server list info.
    >>>> It's supposed to be used like this.

    >
    >>>> ----------
    >>>> SvrList* pList = (SvrList*)malloc(sizeof(
    >>>> SvrList) + svrNum*sizeof(GameSvr));
    >>>> pList->uNum, pList->svr[0], pList->svr[1].... blabla..

    >
    >>> I wouldn't call this fine. Even
    >>> pList->svr[0]
    >>> is accessing the element that is out of array's bounds, and
    >>> that is UB. How come your program is not crashing, or at
    >>> least going crazy? Maybe you are just unlucky to have a bug
    >>> hidden.

    >
    >> It's an old C programmers hack. I've come across this idiom in
    >> lot's old C code, particularly driver and os code. Microsoft
    >> Win32 is rife with it.

    >
    > Except that it's not legal C, either. The C language was
    > carefully specified so that a bounds checking implementation
    > would be legal, and the above will fail in such cases.


    Hence the term 'hack'. ;-)

    > In C++, of course, the declaration he's looking for is
    > std::vector<SvrList>, without any manual new.


    Exactly, unless the op is dealing with some of that legacy Hacked code.

    Jeff
    Jeff Flinn, Aug 19, 2010
    #16
  17. thomas

    Goran Pusic Guest

    On Aug 18, 1:30 pm, thomas <> wrote:
    > Hi, I need your help.
    >
    > ----------
    > struct SvrList{
    >     unsigned int uNum;
    >     GameSvr  svr[0];            //line A};
    >
    > ---------
    >
    > Once I declared a struct like this to store server list info.
    > It's supposed to be used like this.
    >
    > ----------
    > SvrList* pList = (SvrList*)malloc(sizeof(
    > SvrList) + svrNum*sizeof(GameSvr));
    > pList->uNum, pList->svr[0], pList->svr[1].... blabla..
    > ---------
    >
    > The vs2005 compiler gives me the "nonstandard extension used : zero-
    > sized array in struct/union" warning though.
    >
    > I may keep my eye closed to the warning since everything looks fine.
    > But I don't know whether anything bad may happen to me some day due to
    > running environment changes(porting to different platforms, or any
    > other conditions).
    >
    > One work-around way is to declare a one-sized array as struct member,
    > but I didn't see any substantial changes except no warning in this
    > case.
    >
    > Any body give some suggestions?


    If you ever plan to change actual number of elements in your object,
    just drop this crap and use a vector. If not, ponder this (I am
    presuming that your uNum is number of elements you have there):

    template<typename T>
    // hbvla: Heap Based Variable Length Array
    class hbvla : public boost::noncopyable // Can't assign, nor copy-
    construct.
    {
    public:
    void operator delete(void* p)
    {
    delete reinterpret_cast<char*>(p);
    }
    void operator delete(void* p, size_t /*cElements*/)
    { // Compiler calls this in case of exception in ctor
    // that gets called through overloaded operator new (see ^^^).
    // (note matched size_t cElements argument in two cases)
    delete reinterpret_cast<char*>(p);
    }

    static hbvla* create(size_t cElements) { return new (cElements)
    hbvla(cElements); }

    ~hbvla()
    {
    destroy_elements();
    }

    // Trivial helper methods.
    size_t size() const { return _size; }
    T& operator[](size_t i) { assert(i < size()); return _elements; }
    const T& operator[](size_t i) const { assert(i < size()); return
    _elements; }
    T* begin() { return _elements; }
    const T* begin() const { return _elements; }
    T* end() { return _elements+size(); }
    const T* end() const { return _elements+size(); }

    private:
    size_t _size;
    T _elements[1]; // Standard does not allow 0.
    // 1 is OK, but I could have put anything due to particular design.

    // ^^^
    void* operator new(size_t objectSize, size_t cElements)
    { // Only this operator new shall be used.

    // Handle overflow.
    const size_t MaxElements = (SIZE_MAX-objectSize)/cElements;
    if (cElements > MaxElements)
    throw std::bad_alloc();

    return new char[objectSize + cElements*sizeof(T)];
    }

    /*
    Using "standard" operators new with hbvla is does not work, so hide
    them
    (and don't implement them).

    The [] form is not really needed in this case because default ctor
    is hidden,
    but I am leaving it here for informative purposes.

    operator delete[] does not work either.
    */
    void* operator new[](size_t objectSize);
    void* operator new(size_t objectSize);
    void operator delete[](void*);

    typedef hbvla<T> this_type; // helper typedef.

    // ctor: we must empty-construct our _elements from 1 to
    (cElements-1).
    // Empty ctor is dangerous. But since we have a ctor, we don't need
    to write and hide anything.
    hbvla(size_t cElements) : _size(0)
    {
    if (!cElements)
    return; // Strange but possible.

    // Construct elements from 1 to (cElements-1).
    // Use ScopeGuard to destruct partially-constructed array of
    elements.
    _size = 1;
    ScopeGuard elementsGuard = MakeObjGuard(*this,
    &this_type::destroy_elements);
    while (_size<cElements)
    {
    T* p = &_elements[_size];
    new (p) T;
    _size++;
    }
    elementsGuard.Dismiss();
    }

    void destroy_elements()
    { // destroy elements that we create "by hand"
    // (C++ runtime destroys _element[0]).
    std::for_each(begin()+1, end(), &this_type::destroy);
    }

    static void destroy(const T& element)
    {
    element.~T();
    }
    };

    Goran.
    Goran Pusic, Aug 19, 2010
    #17
  18. thomas

    Jorgen Grahn Guest

    On Wed, 2010-08-18, thomas wrote:
    > Hi, I need your help.
    >
    > ----------
    > struct SvrList{
    > unsigned int uNum;
    > GameSvr svr[0]; //line A
    > };

    ....

    > The vs2005 compiler gives me the "nonstandard extension used : zero-
    > sized array in struct/union" warning though.
    >
    > I may keep my eye closed to the warning since everything looks fine.
    > But I don't know whether anything bad may happen to me some day due to
    > running environment changes(porting to different platforms, or any
    > other conditions).
    >
    > One work-around way is to declare a one-sized array as struct member,
    > but I didn't see any substantial changes except no warning in this
    > case.


    That's a substantial change, IMHO. Take gcc for example. There you
    have (last time I checked) no way to disable that warning without
    disabling C++98 conformance. That can be *really* annoying, when you
    have seen the warning daily for a year or two ...

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
    Jorgen Grahn, Aug 19, 2010
    #18
  19. thomas

    Joe Greer Guest

    Vladimir Jovic <> wrote in
    news:i4iuof$s5j$:

    >
    > This looks like a hack. Why declare an array of size 0? Why not use a
    > pointer (like someone suggested)? Is it another (now obsolete and
    > depreciated) way of declaring pointers?


    Indeed, it is a hack, but a useful one. Usually the array is declared of
    size 1 and not 0, but that doesn't make it any prettier. You can't use a
    pointer because that would require 2 allocations and doesn't pass through
    the network near as well. This is a mechanism for creating a struct with
    some dynamically sized data using only 1 buffer. Memory allocation is not
    in anyway cheap (not only to you have the usual overhead, but there is also
    a mutex in there somewhere and possibly a kernel transistion) and in some
    cases, one needs to have only one. This sort of thing can be the
    difference between passing your data in hours instead of days for some
    kinds of applications. You certainly would only use this technique if
    profiling indicated that it was required, but it is useful to understand
    it.

    joe
    Joe Greer, Aug 19, 2010
    #19
  20. thomas

    Joe Greer Guest

    James Kanze <> wrote in news:19c5cd18-a44b-4b5f-b8f8-
    :

    >
    > In C99, flexible array members were introduced to support this
    > idiom. In C++, std::vector does the job a lot cleaner.
    >
    > --
    > James Kanze
    >


    Not really. This hack is used to reduce memory allocations. Using a
    vector doesn't really do that.

    joe
    Joe Greer, Aug 19, 2010
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Zhiqiang Ye
    Replies:
    53
    Views:
    10,215
    Dan Pop
    Jun 28, 2004
  2. Gerard Flanagan
    Replies:
    3
    Views:
    428
    Terry Hancock
    Nov 19, 2005
  3. Replies:
    5
    Views:
    516
    Flash Gordon
    Apr 9, 2006
  4. Replies:
    8
    Views:
    482
    Bob Hairgrove
    Apr 10, 2006
  5. Tuan  Bui
    Replies:
    14
    Views:
    461
    it_says_BALLS_on_your forehead
    Jul 29, 2005
Loading...

Share This Page