0

I have an OVERLAPPED I am trying to put in a known good state. OVERLAPPED is a Windows typedef'd structure provided by the Win32 API. I can't change it.

#pragma push_macro ("WIN32_LEAN_AND MEAN")
#pragma push_macro ("NOMINMAX")

#define WIN32_LEAN_AND MEAN
#define NOMINMAX
#include <windows.h>

struct OverlappedIo : public OVERLAPPED
{
    explicit OverlappedIo()
        : Internal(0), InternalHigh(0), Offset(0), OffsetHigh(0)
        , Pointer(NULL), hEvent(hEvent) { }

    ...
};

#pragma pop_macro ("NOMINMAX")
#pragma pop_macro ("WIN32_LEAN_AND MEAN")

Under MinGW, it results in (it will probably have issues under native Win32; I have not started testing the platform):

g++ -DNDEBUG -g -O2 -march=native -pipe -c network.cpp
In file included from network.cpp:4:0:
network.h: In constructor 'OverlappedIo::OverlappedIo()':
network.h:244:5: error: class 'OverlappedIo' does not have any field n
amed 'Internal'
   : Internal(0), InternalHigh(0), Offset(0), OffsetHigh(0)
     ^
...

I also tried with _OVERLAPPED with the same result. And when I try to provide the missing constructor to perform the C++ initialization (I did not expect this to work, but it was worth a try):

//! OVERLAPPED I/O
OVERLAPPED::OVERLAPPED()
    : Internal(0), InternalHigh(0), Offset(0), OffsetHigh(0), hEvent(NULL) { }

It results in:

In file included from network.cpp:4:0:
network.h:24:24: error: ISO C++ forbids declaration of 'OVERLAPPED' with no type
 [-fpermissive]
 OVERLAPPED::OVERLAPPED()
                        ^

In C++11, I believe I can initialize with curly braces. But its not clear to me how to do it in C++03. Also note this is a simplified example, and the real class is more complex and its trying to provide stronger exception safety. Because of the stronger exception safety, I want to initialize the field, and not memset them or assign them. (Sorry about the word-smithing for "initialize" and "assign").

Is it possible to initialize a typedef'd structure from C?

If so, how do I initialize the fields of the structure in C++03?


Related, here's the struct from <windows.h>:

typedef struct _OVERLAPPED {
    ULONG_PTR Internal;
    ULONG_PTR InternalHigh;
    union {
        struct {
            DWORD Offset;
            DWORD OffsetHigh;
        } DUMMYSTRUCTNAME;
        PVOID Pointer;
    } DUMMYUNIONNAME;

    HANDLE  hEvent;
} OVERLAPPED, *LPOVERLAPPED;

This is related to Are members of a C++ struct initialized to 0 by default? and Correct way of initializing a struct in a class constructor. Its also somewhat related to Do the parentheses after the type name make a difference with new? (I'm trying to avoid the silly rules and simply put an object in a known good state).

Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885

4 Answers4

2

I'd be reluctant to approach the problem in this way: your code could be invalidated if OVERLAPPED changes in any way. Any future additions of members to OVERLAPPED could introduce undefined behaviour into your program if you are expecting all members to be initialised.

Also, note that OVERLAPPED is probably not a polymorphic type so you could be vulnerable to memory leakage as your program develops.

Consider instead having an OVERLAPPED member variable of your class, and in your constructor, initialise the structure to zero using a call to memset.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • It is what it is... Microsoft usually adds an `EX` extension if they change members. For example, [`OSVERSIONINFO`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms724834%28v=vs.85%29.aspx) and [`OSVERSIONINFOEX`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms724833%28v=vs.85%29.aspx). – jww Aug 12 '15 at 07:40
  • Microsoft can't add members to OVERLAPPED, because that would require every program that uses it to be recompiled. – Harry Johnston Aug 13 '15 at 04:50
  • OVERLAPPED is not gonna change. Sometimes you have to be practical when you code, theoretical coding can only take you so far. – Jonathan Potter Aug 13 '15 at 12:43
  • If there is a simple alternative - as there is in this case - then I'd adopt it. "Microsoft can't" should be read as "Microsoft out not to" – Bathsheba Aug 13 '15 at 13:29
1

The member Internal and others are inherited from the base class, and the inherited members cannot be initialized in the derived class's initializer list.

Logically, members of base class are already constructed (and initialized1) by the time the members of derived class start initialization.

1. though in this case, the types are built-in types which don't initialize to any sensible value unless you explicitly initialize them to. The so-called default-initialization for built-in types means uninitialized. So in the derived class constructor body you can assign them with sensible values.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
1

OVERLAPPED is a structure made from PODs, it's pointless to try to pretend it's not. In my opinion there's nothing wrong with initialising using memset:

struct OverlappedIo : public OVERLAPPED
{
    OverlappedIo(HANDLE e = 0)
    {
        memset(this, 0, sizeof(OVERLAPPED));
        hEvent = e;
    }
};
Jonathan Potter
  • 36,172
  • 4
  • 64
  • 79
  • Memset and assignment are not initialization. – jww Aug 12 '15 at 08:28
  • No, but in this case, the end result is the same - the `OverlappedIo` instance has zero values in the `OVERLAPPED` members, minus the `hEvent`. – Remy Lebeau Aug 12 '15 at 20:57
  • I'd be reluctant to pass this to memset in case someone makes your struct a polymorphic type. Then you could blow up your v-table. Oops. – Bathsheba Aug 13 '15 at 05:25
  • @Bathsheba `static_cast(this)` or `&Internal` instead of `this` in the call to `memset` would protect against that. – Jonathan Potter Aug 13 '15 at 05:33
1

This will zero-initialize everything in C++03 (but not C++98):

OVERLAPPED x = OVERLAPPED();

I'm not sure if you really wanted to derive for a good reason or if that was meant to be some sort of hack just for initialization, but if you did:

struct OverlappedIo: OVERLAPPED
{
    OverlappedIo(): OVERLAPPED() {}
    OverlappedIo(HANDLE h): OVERLAPPED() { hEvent = h; }
};

Of course, adding a constructor means you can no longer use aggregate initialization.

In C++11, of course you can just write OVERLAPPED x{};

M.M
  • 138,810
  • 21
  • 208
  • 365
  • *"...some sort of hack just for initialization"* - yep, its an initialization hack. `OverlappedIo` has an overload that can take a `HANDLE`, and trying to plug it into the `OVERLAPPED` in an exception safe way is causing the problems. – jww Aug 12 '15 at 14:00
  • @jww exception safety isnt a problem here , the OVERLAPPED is a POD. In my class example you could add a constructor taking a HANDLE – M.M Aug 12 '15 at 14:04
  • @jww TBH I would just use the OVERLAPPED as-is and write code to set `hEvent`. It's the normal way and what people are used to seeing. – M.M Aug 12 '15 at 14:05