New/delete vs. declare/garbage-collect

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Vincent Fatica

    New/delete vs. declare/garbage-collect

    I noticed that if I give MY_STRUCT a simple c'tor and d'tor, say,

    MY_STRUCT::MY_S TRUCT()
    {
    hEvent = CreateEvent(... );
    }
    MY_STRUCT::~MY_ STRUCT
    {
    CloseHandle(hEv ent);
    }

    then using a local instance via simple declaration,

    INT my_function()
    {
    MY_STRUCT foo;
    // blah
    return 0;
    }

    adds nearly 6KB (most in the .text segment) to my target DLL when compared to
    using it via new/delete. Can someone explain why that happens? The example
    above is just a little simplified. The actual struct has as members a HANDLE, a
    BOOL, and an OVERLAPPED but still the only initialization I want is for the
    HANDLE. Thanks!
    --
    - Vince
  • Vincent Fatica

    #2
    Re: New/delete vs. declare/garbage-collect

    Let me ask the same question another way (more to the point I hope). I use an
    ENUM_INFO (described below) struct like this:

    INT function()
    {
    ENUM_INFO EnumInfo;
    //blah
    EnumWindows(... , &EnumInfo);
    // blah
    return 0;
    }

    The struct and its c'tor and d'tor look like this:

    struct ENUM_INFO
    {
    HANDLE hPipe;
    BOOL bGlobal;
    OVERLAPPED Overlapped;
    ENUM_INFO();
    ~ENUM_INFO();
    };
    ENUM_INFO::ENUM _INFO()
    {
    Overlapped.hEve nt = CreateEvent(NUL L, TRUE, FALSE, NULL);
    Overlapped.Offs et = Overlapped.Offs etHigh = 0;
    };
    ENUM_INFO::~ENU M_INFO()
    {
    //CloseHandle(Ove rlapped.hEvent) ;
    };

    Quite simply, when I uncomment the CloseHandle() call (no other changes
    anywhere) in the d'tor, my target DLL increases in size by 6KB (most in the
    ..text segment). There's nothing special about CloseHandle(); the same will be
    observed with any WIN32 API function in its place(e.g., Beep() or Sleep()).
    What's going on?

    If I instantiate an ENUM_INFO using new/delete, I don't see the size increase.

    Thanks.
    --
    - Vince

    Comment

    • Carl Daniel [VC++ MVP]

      #3
      Re: New/delete vs. declare/garbage-collect

      Vincent Fatica wrote:
      Let me ask the same question another way (more to the point I hope).
      I use an ENUM_INFO (described below) struct like this:
      >
      INT function()
      {
      ENUM_INFO EnumInfo;
      //blah
      EnumWindows(... , &EnumInfo);
      // blah
      return 0;
      }
      >
      The struct and its c'tor and d'tor look like this:
      >
      struct ENUM_INFO
      {
      HANDLE hPipe;
      BOOL bGlobal;
      OVERLAPPED Overlapped;
      ENUM_INFO();
      ~ENUM_INFO();
      };
      ENUM_INFO::ENUM _INFO()
      {
      Overlapped.hEve nt = CreateEvent(NUL L, TRUE, FALSE, NULL);
      Overlapped.Offs et = Overlapped.Offs etHigh = 0;
      };
      ENUM_INFO::~ENU M_INFO()
      {
      //CloseHandle(Ove rlapped.hEvent) ;
      };
      >
      Quite simply, when I uncomment the CloseHandle() call (no other
      changes anywhere) in the d'tor, my target DLL increases in size by
      6KB (most in the .text segment). There's nothing special about
      CloseHandle(); the same will be observed with any WIN32 API function
      in its place(e.g., Beep() or Sleep()). What's going on?
      >
      If I instantiate an ENUM_INFO using new/delete, I don't see the size
      increase.
      How many places in your code are you creating local variables of this type?
      Every single one of them will entail adding code to the function epilog to
      destroy the object that won't be there unless you explicitly delete it.
      Probably more importantly, having a destructor will cause any function
      containing the object to have an exception frame and exception handling code
      generated for it if you're compiling with -GX, -EHa or -EHs (in other words,
      if you have exception handling turned on - it's on by default in 2005). In
      exchange for that extra code size you code code will behave correctly in the
      face of exceptions.

      -cd


      Comment

      • Vincent Fatica

        #4
        Re: New/delete vs. declare/garbage-collect

        On Thu, 14 Dec 2006 21:12:40 -0800, "Carl Daniel [VC++ MVP]"
        <cpdaniel_remov e_this_and_nosp am@mvps.org.nos pamwrote:
        >Vincent Fatica wrote:
        >Let me ask the same question another way (more to the point I hope).
        >I use an ENUM_INFO (described below) struct like this:
        >>
        >INT function()
        >{
        >ENUM_INFO EnumInfo;
        >//blah
        >EnumWindows(.. ., &EnumInfo);
        >// blah
        >return 0;
        >}
        >>
        >The struct and its c'tor and d'tor look like this:
        >>
        >struct ENUM_INFO
        >{
        >HANDLE hPipe;
        >BOOL bGlobal;
        >OVERLAPPED Overlapped;
        >ENUM_INFO();
        >~ENUM_INFO() ;
        >};
        >ENUM_INFO::ENU M_INFO()
        >{
        >Overlapped.hEv ent = CreateEvent(NUL L, TRUE, FALSE, NULL);
        >Overlapped.Off set = Overlapped.Offs etHigh = 0;
        >};
        >ENUM_INFO::~EN UM_INFO()
        >{
        >//CloseHandle(Ove rlapped.hEvent) ;
        >};
        >>
        >Quite simply, when I uncomment the CloseHandle() call (no other
        >changes anywhere) in the d'tor, my target DLL increases in size by
        >6KB (most in the .text segment). There's nothing special about
        >CloseHandle( ); the same will be observed with any WIN32 API function
        >in its place(e.g., Beep() or Sleep()). What's going on?
        >>
        >If I instantiate an ENUM_INFO using new/delete, I don't see the size
        >increase.
        >
        >How many places in your code are you creating local variables of this type?
        Only one place.
        >Every single one of them will entail adding code to the function epilog to
        >destroy the object that won't be there unless you explicitly delete it.
        >Probably more importantly, having a destructor will cause any function
        >containing the object to have an exception frame and exception handling code
        >generated for it if you're compiling with -GX, -EHa or -EHs (in other words,
        >if you have exception handling turned on - it's on by default in 2005). In
        >exchange for that extra code size you code code will behave correctly in the
        >face of exceptions.
        Well, it looks like compiler madness to me. If I make things a bit more
        complicated, like this:

        ENUM_INFO::ENUM _INFO(BOOL boo, HANDLE hoo)
        {
        bGlobal = boo;
        hPipe = hoo;
        Overlapped.hEve nt = CreateEvent(NUL L, TRUE, FALSE, NULL);
        Overlapped.Offs et = Overlapped.Offs etHigh = 0;
        };

        ENUM_INFO::~ENU M_INFO()
        {
        CloseHandle(Ove rlapped.hEvent) ;
        CloseHandle(hPi pe);
        };

        And use it as a local variable like this:

        ENUM_INFO EnumInfo(strist r(psz, L"/G") ? TRUE : FALSE,
        CreateNamedPipe (szPipeName, PIPE_ACCESS_INB OUND | FILE_FLAG_OVERL APPED,
        PIPE_WAIT, 1, 0, sizeof(EVENT), 2000, NULL));

        My DLL drops the 6KB it gained from the set-up mentioned above.
        --
        - Vince

        Comment

        • Vincent Fatica

          #5
          Re: New/delete vs. declare/garbage-collect

          On 15 Dec 2006 00:54:49 -0500, Vincent Fatica <abuse@localhos t.comwrote:
          >On Thu, 14 Dec 2006 21:12:40 -0800, "Carl Daniel [VC++ MVP]"
          ><cpdaniel_remo ve_this_and_nos pam@mvps.org.no spamwrote:
          >
          >>Vincent Fatica wrote:
          >>Let me ask the same question another way (more to the point I hope).
          >>I use an ENUM_INFO (described below) struct like this:
          >>>
          >>INT function()
          >>{
          >>ENUM_INFO EnumInfo;
          >>//blah
          >>EnumWindows(. .., &EnumInfo);
          >>// blah
          >>return 0;
          >>}
          >>>
          >>The struct and its c'tor and d'tor look like this:
          >>>
          >>struct ENUM_INFO
          >>{
          >>HANDLE hPipe;
          >>BOOL bGlobal;
          >>OVERLAPPED Overlapped;
          >>ENUM_INFO() ;
          >>~ENUM_INFO( );
          >>};
          >>ENUM_INFO::EN UM_INFO()
          >>{
          >>Overlapped.hE vent = CreateEvent(NUL L, TRUE, FALSE, NULL);
          >>Overlapped.Of fset = Overlapped.Offs etHigh = 0;
          >>};
          >>ENUM_INFO::~E NUM_INFO()
          >>{
          >>//CloseHandle(Ove rlapped.hEvent) ;
          >>};
          >>>
          >>Quite simply, when I uncomment the CloseHandle() call (no other
          >>changes anywhere) in the d'tor, my target DLL increases in size by
          >>6KB (most in the .text segment). There's nothing special about
          >>CloseHandle() ; the same will be observed with any WIN32 API function
          >>in its place(e.g., Beep() or Sleep()). What's going on?
          >>>
          >>If I instantiate an ENUM_INFO using new/delete, I don't see the size
          >>increase.
          >>
          >>How many places in your code are you creating local variables of this type?
          >
          >Only one place.
          >
          >>Every single one of them will entail adding code to the function epilog to
          >>destroy the object that won't be there unless you explicitly delete it.
          >>Probably more importantly, having a destructor will cause any function
          >>containing the object to have an exception frame and exception handling code
          >>generated for it if you're compiling with -GX, -EHa or -EHs (in other words,
          >>if you have exception handling turned on - it's on by default in 2005). In
          >>exchange for that extra code size you code code will behave correctly in the
          >>face of exceptions.
          >
          >Well, it looks like compiler madness to me. If I make things a bit more
          >complicated, like this:
          >
          >ENUM_INFO::ENU M_INFO(BOOL boo, HANDLE hoo)
          >{
          > bGlobal = boo;
          > hPipe = hoo;
          > Overlapped.hEve nt = CreateEvent(NUL L, TRUE, FALSE, NULL);
          > Overlapped.Offs et = Overlapped.Offs etHigh = 0;
          >};
          >
          >ENUM_INFO::~EN UM_INFO()
          >{
          > CloseHandle(Ove rlapped.hEvent) ;
          > CloseHandle(hPi pe);
          >};
          >
          >And use it as a local variable like this:
          >
          >ENUM_INFO EnumInfo(strist r(psz, L"/G") ? TRUE : FALSE,
          > CreateNamedPipe (szPipeName, PIPE_ACCESS_INB OUND | FILE_FLAG_OVERL APPED,
          > PIPE_WAIT, 1, 0, sizeof(EVENT), 2000, NULL));
          >
          >My DLL drops the 6KB it gained from the set-up mentioned above.
          Whereas (here's the real corker) if, in the code just above, I instantiate it
          thus:

          ENUM_INFO EnumInfo(FALSE, NULL);

          (regardless of whether I later set the real (desired) values of hPipe and
          bGlogal) the DLL size jumps back up 6KB. BTW, it's a release build.
          --
          - Vince

          Comment

          • Arnaud Debaene

            #6
            Re: New/delete vs. declare/garbage-collect


            "Vincent Fatica" <abuse@localhos t.coma écrit dans le message de news:
            45823c36$1@news .vefatica.net.. .
            >>ENUM_INFO::EN UM_INFO(BOOL boo, HANDLE hoo)
            >>{
            >bGlobal = boo;
            >hPipe = hoo;
            >Overlapped.hEv ent = CreateEvent(NUL L, TRUE, FALSE, NULL);
            >Overlapped.Off set = Overlapped.Offs etHigh = 0;
            >>};
            >>
            >>ENUM_INFO::~E NUM_INFO()
            >>{
            >CloseHandle(Ov erlapped.hEvent );
            >CloseHandle(hP ipe);
            >>};
            >>
            >>And use it as a local variable like this:
            >>
            >>ENUM_INFO EnumInfo(strist r(psz, L"/G") ? TRUE : FALSE,
            >CreateNamedPip e(szPipeName, PIPE_ACCESS_INB OUND | FILE_FLAG_OVERL APPED,
            >PIPE_WAIT, 1, 0, sizeof(EVENT), 2000, NULL));
            >>
            >>My DLL drops the 6KB it gained from the set-up mentioned above.
            >
            Whereas (here's the real corker) if, in the code just above, I instantiate
            it
            thus:
            >
            ENUM_INFO EnumInfo(FALSE, NULL);
            >
            (regardless of whether I later set the real (desired) values of hPipe and
            bGlogal) the DLL size jumps back up 6KB. BTW, it's a release build.
            It's hard to be sure of anything without a complete sample (complete code +
            compiler settings + compiler version), but I would say that when you see the
            6 Kb increase, it's because the compiler decides that you need exception
            safety mechanisms : that is, you've got a local (stack) variable with a
            non-trivial destructor. In this situation, in order to be exception-safe,
            the compiler needs to add an exception frame to the function where this
            variable is declared, and it needs to add all it's internal machinery that
            is used during stack-unwinding (eg, "catch" handlers tables, with filters by
            exception types....) The stack-unwinding machinery is quite complex and need
            a lot of static data (therefore the .text section increase).

            However, I bet most of the 6 Ko increase is to be paid only once (that is,
            if you add a second function that also allocates an ENUM_INFO on the stack,
            you will see a much smaller increase).

            Arnaud
            MVP - VC


            Comment

            • Vincent Fatica

              #7
              Re: New/delete vs. declare/garbage-collect

              On Fri, 15 Dec 2006 08:05:28 +0100, "Arnaud Debaene" <adebaene@clu b-internet.fr>
              wrote:
              >
              >"Vincent Fatica" <abuse@localhos t.coma écrit dans le message de news:
              >45823c36$1@new s.vefatica.net. ..
              >
              >>>ENUM_INFO::E NUM_INFO(BOOL boo, HANDLE hoo)
              >>>{
              >>bGlobal = boo;
              >>hPipe = hoo;
              >>Overlapped.hE vent = CreateEvent(NUL L, TRUE, FALSE, NULL);
              >>Overlapped.Of fset = Overlapped.Offs etHigh = 0;
              >>>};
              >>>
              >>>ENUM_INFO::~ ENUM_INFO()
              >>>{
              >>CloseHandle(O verlapped.hEven t);
              >>CloseHandle(h Pipe);
              >>>};
              >>>
              >>>And use it as a local variable like this:
              >>>
              >>>ENUM_INFO EnumInfo(strist r(psz, L"/G") ? TRUE : FALSE,
              >>CreateNamedPi pe(szPipeName, PIPE_ACCESS_INB OUND | FILE_FLAG_OVERL APPED,
              >>PIPE_WAIT, 1, 0, sizeof(EVENT), 2000, NULL));
              >>>
              >>>My DLL drops the 6KB it gained from the set-up mentioned above.
              >>
              >Whereas (here's the real corker) if, in the code just above, I instantiate
              >it
              >thus:
              >>
              >ENUM_INFO EnumInfo(FALSE, NULL);
              >>
              >(regardless of whether I later set the real (desired) values of hPipe and
              >bGlogal) the DLL size jumps back up 6KB. BTW, it's a release build.
              >
              >It's hard to be sure of anything without a complete sample (complete code +
              >compiler settings + compiler version), but I would say that when you see the
              >6 Kb increase, it's because the compiler decides that you need exception
              >safety mechanisms : that is, you've got a local (stack) variable with a
              >non-trivial destructor. In this situation, in order to be exception-safe,
              >the compiler needs to add an exception frame to the function where this
              >variable is declared, and it needs to add all it's internal machinery that
              >is used during stack-unwinding (eg, "catch" handlers tables, with filters by
              >exception types....) The stack-unwinding machinery is quite complex and need
              >a lot of static data (therefore the .text section increase).
              I don't know enough to say whether that's likely or not. But IMHO,

              ENUM_INFO EnumInfo(FALSE, NULL);

              (which causes the 6KB increase) looks safer than

              ENUM_INFO EnumInfo(strist r(psz, L"/G") ? TRUE : FALSE,
              CreateNamedPipe (szPipeName, PIPE_ACCESS_INB OUND | FILE_FLAG_OVERL APPED,
              PIPE_WAIT, 1, 0, sizeof(EVENT), 2000, NULL));

              which doesn't.
              --
              - Vince

              Comment

              • Vincent Fatica

                #8
                Re: New/delete vs. declare/garbage-collect

                On 15 Dec 2006 02:33:22 -0500, Vincent Fatica <abuse@localhos t.comwrote:
                >On Fri, 15 Dec 2006 08:05:28 +0100, "Arnaud Debaene" <adebaene@clu b-internet.fr>
                >wrote:
                >
                >>
                >>"Vincent Fatica" <abuse@localhos t.coma écrit dans le message de news:
                >>45823c36$1@ne ws.vefatica.net ...
                >>
                >>>>ENUM_INFO:: ENUM_INFO(BOOL boo, HANDLE hoo)
                >>>>{
                >>>bGlobal = boo;
                >>>hPipe = hoo;
                >>>Overlapped.h Event = CreateEvent(NUL L, TRUE, FALSE, NULL);
                >>>Overlapped.O ffset = Overlapped.Offs etHigh = 0;
                >>>>};
                >>>>
                >>>>ENUM_INFO:: ~ENUM_INFO()
                >>>>{
                >>>CloseHandle( Overlapped.hEve nt);
                >>>CloseHandle( hPipe);
                >>>>};
                >>>>
                >>>>And use it as a local variable like this:
                >>>>
                >>>>ENUM_INFO EnumInfo(strist r(psz, L"/G") ? TRUE : FALSE,
                >>>CreateNamedP ipe(szPipeName, PIPE_ACCESS_INB OUND | FILE_FLAG_OVERL APPED,
                >>>PIPE_WAIT, 1, 0, sizeof(EVENT), 2000, NULL));
                >>>>
                >>>>My DLL drops the 6KB it gained from the set-up mentioned above.
                >>>
                >>Whereas (here's the real corker) if, in the code just above, I instantiate
                >>it
                >>thus:
                >>>
                >>ENUM_INFO EnumInfo(FALSE, NULL);
                >>>
                >>(regardless of whether I later set the real (desired) values of hPipe and
                >>bGlogal) the DLL size jumps back up 6KB. BTW, it's a release build.
                >>
                >>It's hard to be sure of anything without a complete sample (complete code +
                >>compiler settings + compiler version), but I would say that when you see the
                >>6 Kb increase, it's because the compiler decides that you need exception
                >>safety mechanisms : that is, you've got a local (stack) variable with a
                >>non-trivial destructor. In this situation, in order to be exception-safe,
                >>the compiler needs to add an exception frame to the function where this
                >>variable is declared, and it needs to add all it's internal machinery that
                >>is used during stack-unwinding (eg, "catch" handlers tables, with filters by
                >>exception types....) The stack-unwinding machinery is quite complex and need
                >>a lot of static data (therefore the .text section increase).
                >
                >I don't know enough to say whether that's likely or not. But IMHO,
                >
                > ENUM_INFO EnumInfo(FALSE, NULL);
                >
                >(which causes the 6KB increase) looks safer than
                >
                > ENUM_INFO EnumInfo(strist r(psz, L"/G") ? TRUE : FALSE,
                > CreateNamedPipe (szPipeName, PIPE_ACCESS_INB OUND | FILE_FLAG_OVERL APPED,
                > PIPE_WAIT, 1, 0, sizeof(EVENT), 2000, NULL));
                >
                >which doesn't.
                FWIW, I'm building my DLL with VS2002/SP1. Ths settings are:

                /O1 /Ob1 /Os /Oy /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D
                "EVENT2_EXPORTS " /D "_UNICODE" /D "UNICODE" /D "_WINDLL" /GF /FD /EHsc /ML /Gy
                /Zc:wchar_t /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /nologo /c /Wp64 /Zi /TP

                /OUT:"Release/ev.dll" /INCREMENTAL:NO /NOLOGO /DLL /DEF:"event.def"
                /SUBSYSTEM:WINDO WS /OPT:REF /OPT:ICF /OPT:NOWIN98 /IMPLIB:"Release/event2.lib"
                /MACHINE:IX86 g:\Projects\eve nt2\release\\ta kecmd.lib kernel32.lib user32.lib
                gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib
                oleaut32.lib uuid.lib odbc32.lib odbccp32.lib release\TakeCmd .lib
                --
                - Vince

                Comment

                • Ben Voigt

                  #9
                  Re: New/delete vs. declare/garbage-collect


                  "Vincent Fatica" <abuse@localhos t.comwrote in message
                  news:45824fc2$1 @news.vefatica. net...
                  On Fri, 15 Dec 2006 08:05:28 +0100, "Arnaud Debaene"
                  <adebaene@clu b-internet.fr>
                  wrote:
                  >
                  >>
                  >>"Vincent Fatica" <abuse@localhos t.coma écrit dans le message de news:
                  >>45823c36$1@ne ws.vefatica.net ...
                  >>
                  >>>>ENUM_INFO:: ENUM_INFO(BOOL boo, HANDLE hoo)
                  >>>>{
                  >>>bGlobal = boo;
                  >>>hPipe = hoo;
                  >>>Overlapped.h Event = CreateEvent(NUL L, TRUE, FALSE, NULL);
                  >>>Overlapped.O ffset = Overlapped.Offs etHigh = 0;
                  >>>>};
                  >>>>
                  >>>>ENUM_INFO:: ~ENUM_INFO()
                  >>>>{
                  >>>CloseHandle( Overlapped.hEve nt);
                  >>>CloseHandle( hPipe);
                  >>>>};
                  >>>>
                  >
                  I don't know enough to say whether that's likely or not. But IMHO,
                  >
                  ENUM_INFO EnumInfo(FALSE, NULL);
                  >
                  (which causes the 6KB increase) looks safer than
                  >
                  ENUM_INFO EnumInfo(strist r(psz, L"/G") ? TRUE : FALSE,
                  CreateNamedPipe (szPipeName, PIPE_ACCESS_INB OUND | FILE_FLAG_OVERL APPED,
                  PIPE_WAIT, 1, 0, sizeof(EVENT), 2000, NULL));
                  Not from the compiler's point of view, because in the second case, all the
                  real work is done *before* calling the constructor. Any exceptions will
                  cause the object not to be constructed, and therefore not need destruction.

                  This extra work for exception handling is a very good thing. With stack
                  objects, you are guaranteed to (try to) free the kernel objects if an
                  exception is thrown after the object is created. In fact, you should deploy
                  the RAII idiom completely, so that every kernel object is in a separate
                  variable that knows to free it. These can all be member variables of
                  ENUM_INFO if you want. But, let's look at your code.

                  If the CreateEvent fails in the constructor, you may never CloseHandle on
                  the pipe. You don't try to use the event handle in the constructor, so the
                  object becomes live. Then, when you try to use the event handle
                  (WaitForMultipl eObjects perhaps) you could get an access violation. The
                  compiler will begin stack unwinding, and call your destructor. The
                  destructor call to CloseHandle the event fails with another access
                  violation, immediately leaving the destructor. The pipe would not be
                  closed.

                  Using individual RAII objects will cause them to be separately destructed,
                  even if other destructors fail.

                  Getting all this right using new/delete would be:
                  (1) a big pain
                  (2) the __try/__finally logic would probably add the same 6kb as letting the
                  compiler use unwinding.

                  If you are willing to accept process termination in case of any failure
                  whatsoever, then disable exceptions. Otherwise, appreciate that the 6kb is
                  necessary and generated by the compiler so you don't have to do it by hand.
                  >
                  which doesn't.
                  --
                  - Vince

                  Comment

                  • Vincent Fatica

                    #10
                    Re: New/delete vs. declare/garbage-collect

                    On Fri, 15 Dec 2006 08:05:28 +0100, "Arnaud Debaene" <adebaene@clu b-internet.fr>
                    wrote:
                    >It's hard to be sure of anything without a complete sample (complete code +
                    >compiler settings + compiler version), but I would say that when you see the
                    >6 Kb increase, it's because the compiler decides that you need exception
                    >safety mechanisms : that is, you've got a local (stack) variable with a
                    >non-trivial destructor. In this situation, in order to be exception-safe,
                    >the compiler needs to add an exception frame to the function where this
                    >variable is declared, and it needs to add all it's internal machinery that
                    >is used during stack-unwinding (eg, "catch" handlers tables, with filters by
                    >exception types....) The stack-unwinding machinery is quite complex and need
                    >a lot of static data (therefore the .text section increase).
                    Well, Arnaud, that seems very likely. When I remove /EHsc I can no longer cause
                    the size increase. But I must repeat that whether or not the compiler decides
                    to add that code is quite serendipitous. In the latest version, with the most
                    the most going on in the c'tor and d'tor (below), the safety mechanisms are not
                    added.

                    ENUM_INFO::ENUM _INFO(BOOL bg)
                    {
                    WCHAR szPipeName[32];
                    Sprintf(szPipeN ame, L"%s%lu", szPipeNameStub, g.dwPid);
                    hPipe = CreateNamedPipe (szPipeName, PIPE_ACCESS_INB OUND |
                    FILE_FLAG_OVERL APPED, PIPE_WAIT, 1, 0, sizeof(EVENT), 2000, NULL);
                    Overlapped.hEve nt = CreateEvent(NUL L, TRUE, FALSE, NULL);
                    Overlapped.Offs et = Overlapped.Offs etHigh = 0;
                    bGlobal = bg;
                    };

                    ENUM_INFO::~ENU M_INFO()
                    {
                    if ( Overlapped.hEve nt ) CloseHandle(Ove rlapped.hEvent) ;
                    if ( hPipe ) CloseHandle( hPipe );
                    };

                    INT WINAPI function(WCHAR *psz)
                    {
                    // blah
                    // instantiation
                    ENUM_INFO EnumInfo(strist r(psz, L"/G") ? TRUE : FALSE);
                    if ( !EnumInfo.hPipe || !EnumInfo.Overl apped.hEvent )
                    return -1; // do more?
                    EnumWindows(... , &EnumInfo);
                    // blah
                    return 0;
                    }
                    --
                    - Vince

                    Comment

                    • Vincent Fatica

                      #11
                      Re: New/delete vs. declare/garbage-collect

                      On Fri, 15 Dec 2006 11:24:10 -0600, "Ben Voigt" <rbv@nospam.nos pamwrote:
                      >But, let's look at your code.
                      >
                      >If the CreateEvent fails in the constructor, you may never CloseHandle on
                      >the pipe. You don't try to use the event handle in the constructor, so the
                      >object becomes live. Then, when you try to use the event handle
                      >(WaitForMultip leObjects perhaps) you could get an access violation. The
                      >compiler will begin stack unwinding, and call your destructor. The
                      >destructor call to CloseHandle the event fails with another access
                      >violation, immediately leaving the destructor. The pipe would not be
                      >closed.
                      Thanks Ben. I wasn't worrying much about catching errors when trying to sort
                      out the 6KB thing. I have this sort of thing now (paraphrased)

                      FOO::FOO()
                      {
                      handle1 = ... // NULL on fail
                      }
                      FOO:~FOO()
                      {
                      if (handle1) CloseHandle(han dle1);
                      }

                      code:

                      FOO foo;
                      if ( !foo.handle1 ) ... // don't do anything rash
                      else ... // life is right
                      --
                      - Vince

                      Comment

                      Working...