Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. another preference question....

another preference question....

Scheduled Pinned Locked Moved The Lounge
questionc++designcollaborationperformance
84 Posts 54 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Janzen

    If you want to bring it up with the team again, and I would personally, the name of the pattern that you use is called Resource Acquisition Is Initialization. The best reason for using this pattern, in my opinion, is that it is exception safe. If an exception happens it the object will be cleaned up automatically when the destructor is called, without you having to specifically needing to call the cleanup method. A quick google search for RAII will bring up plenty of reasons to discuss with your team should you ever find yourself in that argument again.

    N Offline
    N Offline
    Nemanja Trifunovic
    wrote on last edited by
    #33

    Janzen wrote:

    the name of the pattern that you use is called Resource Acquisition Is Initialization.

    Amen. Although it is surprising how many people refuse to grasp it.


    Programming Blog utf8-cpp

    1 Reply Last reply
    0
    • R Rama Krishna Vavilala

      I think it depends. Normally I would lean towards the constructor based initialization but not always. In the end you have to decide whether it improves code readability. Here is an horror story which ought to go to the Coding Horrors. In my previous company, I was fixing an issue and in that file I found the following code:

      void PostInvoice()
      {
      ApbhTivhStatusChange * pChg = new ApbhTivhStatusChange(m_pContext);
      delete pChg;

      //Some other code follows this is where the real bug I was
      //supposed to fix was
      }

      After fixing the issue, I removed the first 3 lines of the function thinking that it was not doing anything as the process function was commented out. My bug fix worked correctly and I checked it in. I modified like this:

      void PostInvoice()
      {
      //Some other code follows this is where the real bug I was
      //supposed to fix was
      }

      Later on is QA testing it was discovered that seem other piece of application functionality broke. It was embarrassing to find that the code I removed caused the issue. It was not a big issue to discover that the work was being done in the constructor and destructor of ApbhTivhStatusChange class.

      class ApbhTivhStatusChange
      {
      private:
      Context* m_pContext;

      public:
      ApbhTivhStatusChange(Context* pContext)
      {
      pContext->ConnectToDatabase();
      pContext->BalanceInvoice();
      }

      ~ApbhTivhStatusChange()
      {
      pContext->Cleanup();
      }
      }

      The above code was poorly written even though it worked. It caused a huge confusion. But one thing is for sure, you should always add clean up code in the destructor. There are very few cases where I found that it is not advisable to do so and of course you need to make sure that the destructors do not throw any exceptions but at the same time they log the exceptions.

      Co-Author ASP.NET AJAX in Action

      B Offline
      B Offline
      Big Daddy Farang
      wrote on last edited by
      #34

      Whoever wrote the original PostInvoice() and did not comment the purpose of the first two lines should be taken out and shot. BDF

      R 1 Reply Last reply
      0
      • B Big Daddy Farang

        Whoever wrote the original PostInvoice() and did not comment the purpose of the first two lines should be taken out and shot. BDF

        R Offline
        R Offline
        Rama Krishna Vavilala
        wrote on last edited by
        #35

        The code actually evolved passing through several developers, the original developer might have done it correctly. It was probably the idea of a later developer who was a newbie to use the constructor an destructor to do all the work.

        Co-Author ASP.NET AJAX in Action

        E 1 Reply Last reply
        0
        • R Rama Krishna Vavilala

          The code actually evolved passing through several developers, the original developer might have done it correctly. It was probably the idea of a later developer who was a newbie to use the constructor an destructor to do all the work.

          Co-Author ASP.NET AJAX in Action

          E Offline
          E Offline
          El Corazon
          wrote on last edited by
          #36

          Rama Krishna Vavilala wrote:

          The code actually evolved passing through several developers, the original developer might have done it correctly. It was probably the idea of a later developer who was a newbie to use the constructor an destructor to do all the work.

          we had something like that happen to us. It was in an Ascii to Latitude/Longitude routine. I forget the name of the method, but it supported several types of latitude or longitude references (dd.decimal or dd mm.dec or dd mm ss.dec). Another programmer got ahold of the method and continued addition additional inputs beyond even latitude and longitude, attempting the equivalent generalality of a scanf() for geodetic values. Pass about 6 months and no one knew these changes occured and everything was still going fine, until we tried to run a specific data set in a specific format, and intermittent jumps were occuring in the data. Turns out the new changes were not thread-safe, and the routine had grown so complex supporting so many types that it was a pain to track down! mind you, the method was still directly referenced as something to the extent of ascii 2 latlong in the name, so everyone thought it still did just that.

          _________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)

          1 Reply Last reply
          0
          • M Miszou

            Nemanja Trifunovic wrote:

            constructors can't return values to tell us if something went wrong

            I've recently started using a library that makes all constructors inaccessible, and all objects must be created by a overloads of a static Create method on the object. eg:

            class MyClass
            {
                private MyClass() {}
            
                public static MyClass Create()
                {
                    return new MyClass();
                }
            }
            

            I first thought that this was because constructors could not return failure codes, but as I type this, I realize that a static Create method with a specific return type can't return a status code either! Then I thought it was for serializing the object or something of that nature, but with reflection (in .NET), you can call a constructor as easily as any other method. My final thoughts on this, are that the Create method does not have to return a specific instance, while a constructor does. This means that in a complex hierarchy, you can be given a descendent object instead of the object you asked actually asked for, depending on how the Create method works. A highly contrived example:

            class ClassA
            {
                private ClassA() {}
            
                public static ClassA Create( int x )
                {
                    if ( x < 0 )
                        return new ClassA();
                    else
                        return ClassB.Create();
                }
            }
            
            class ClassB : ClassA
            {
                private ClassB() {}
            
                public static ClassB()
                {
                    return new ClassB();
                }
            }
            
            static void main()
            {
                ClassA myClass = ClassA.Create( 3 ); // Will really create a ClassB
            }
            

            Is this what it's used for? Or am I heading into La-La Land with this line of thinking?


            Sunrise Wallpaper Project | The StartPage Randomizer | A Random Web Page

            D Offline
            D Offline
            DavidNohejl
            wrote on last edited by
            #37

            http://en.wikipedia.org/wiki/Factory_method_pattern[^]


            [My Blog]
            "Visual studio desperately needs some performance improvements. It is sometimes almost as slow as eclipse." - Rüdiger Klaehn
            "Real men use mspaint for writing code and notepad for designing graphics." - Anna-Jayne Metcalfe

            1 Reply Last reply
            0
            • B Bijesh

              Just to add on to what others have said, even with exceptions, in C++, an exception raised inside a constructor still poses a problem. For example, if you are using a pointer, and the constructor thew an exception, do you delete the object through that pointer? Is it needed/safe? It was safer to do just simple initialisations within the constructor, and put anything that can go wrong in a separate method.

              J Offline
              J Offline
              James R Twine
              wrote on last edited by
              #38

              Bijesh wrote:

              For example, if you are using a pointer, and the constructor thew an exception, do you delete the object through that pointer?

              If the object was allocated using the non-placement (i.e. normal) version of new, the object is supposed to be "undone".  However (last checked on VC++ 6.0), members of that object will only be cleaned up if they themselves were fully constructed at the time of the exception, so the object is destructed (as best it could be), new returns NULL, so there is nothing to call delete on.    If the object was allocated on the stack, that stack context will be destroyed by the stack unwinding that takes place, so again there is nothing to manually destroy/cleanup.    Things change when you are dealing with placement new because you are basically directly calling the constructor to construct an object in a pre-allocated block of memory.  What you do in that case depends on what you are using the block of memory for.  You may free the entire block, or simply log the exception and continue with the next object reusing that block of memory.  You just have to watch out for that exception so that you do not end up using that "partially constructed" object (which I have done before :doh: - that is why I know it is possible, and know that the vtbl is/was the last thing to get initialized during construction).    Not many developers need to implement their own fixed-size-block-allocator-based object cache, or otherwise deal with placement new, so issues with throwing exceptions from constructors is a non-issue for many.    Peace!

              -=- James
              Please rate this message - let me know if I helped or not! * * * If you think it costs a lot to do it right, just wait until you find out how much it costs to do it wrong!
              Avoid driving a vehicle taller than you and remember that Professional Driver on Closed Course does not mean your Dumb Ass on a Public Road!
              See DeleteFXPFiles

              B 1 Reply Last reply
              0
              • E El Corazon

                Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?

                _________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)

                P Offline
                P Offline
                PIEBALDconsult
                wrote on last edited by
                #39

                One of the shortcomings of constructors (at least in the languages I've used) is that they aren't virtual. In this example, the Child class must define a constructor, but it simply calls the base constructor without adding any unique behaviour. If the constructor were inherited by the Child this wouldn't be necessary.

                public class Base
                {
                public string Name ;
                public Base ( string Name )
                {
                this.Name = Name ;
                }
                }

                public class Child : Base
                {
                public Child ( string Name ) : base ( Name ) {}
                }

                By defining a virtual Initialize method to do what the constructor would do (and allowing the compiler to provide an empty parameterless constructor), you get the desired behaviour.

                public class Base
                {
                public string Name ;
                public virtual Base Initialize ( string Name )
                {
                this.Name = Name ;
                return ( this ) ;
                }
                }

                public class Child : Base {}

                As you can see, the Child class needn't define a constructor, the empty parameterless constructor the compiler adds is enough and then the Child inherits the Initialize method, which it may override if and only if it needs to. (Note that Initialize returns a reference to the calling instance.) On the downside, using a class like this is a litte more complex, basically:

                Child c = new Child() ;
                c.Initialize ( "Zaphod" ) ;

                or

                Child c = (Child) (new Child()).Initialize ( "Zaphod" ) ;

                As you can see, saving time and effort writing and maintaining the classes costs some time and effort using the classes, so you have to decide for yourself which you prefer. I'd much rather have virtual constructors.

                1 Reply Last reply
                0
                • E El Corazon

                  Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?

                  _________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)

                  P Offline
                  P Offline
                  peterchen
                  wrote on last edited by
                  #40

                  Reading the above comments it seems that most people agree on a RAII model anyway. Requiring a sequence of steps to use simply sucks. RULE: the external interface should provide no surprises, and reduce complexity as much as possible. Both are usually violated by a "required sequence" class. So constructor-initialization and destructor-cleanup are my first choice, too, but there's a small footnote I'd add. In C++, creating a dynamic object is - compared to a "normal" data member - considered expensive and painful (unless you use smart pointers, which usually make it bearable). Also, there are some aggregation initialization scenarios where a direct initialization isn't feasible, e.g.: class Gamma { public: void Gamma(Container * container) { m_container * container; } }; class Container { Gamma m_gamma; public: Container() : m_gamma(this) {} **//BAD IDEA!** } You can now either make gamma dynamic: class Container { scoped_ptr m_gamma; public: Container() { m_gamma.reset(new Gamma(this)); } } or you need to use an Init-Method. Still, in this case, there's a fixed patthern (rather two of them) I strictly follow:

                  class Gamma
                  {
                  public:
                  Gamma() {... } // valid "not open" initialization
                  bool IsOpen();
                  void/errcode Open(...); // fails if IsOpen()
                  void Close(); // fails if IsOpen
                  ~Gamma() { if (IsOpen() Close(); }
                  };

                  i.e. the class is initialized correctly, if a resource is acquire can be queried using IsOpen, and the destructor cleans up if you don't close. (so Close is just an "early release of the resource", rather than a mandatory cleanup) Further, the class state must remain well-formed if you try to access the ressource if it isn*t acquired. Also, you must be able to use open and close a single instance as often as you like. One shot classes and "you can't call foo ever again after you called bar" are - unless this is a requirement of the ressource - teh h3ll. (just for the curious: the second pattern is just more relaxed, for the lazy me:

                  class Gamma
                  {
                  public:
                  bool IsOpen();
                  void/errcode Open() { Close(); ... }
                  void Close() { if (IsOpen()) { ... } }
                  ~Gamma() { Close(); }
                  }

                  the idea here is to move the IsOpen() calls from the caller into the class, so caller has to type less


                  We are a big screwed up dysfunctional psychotic happy fami

                  1 Reply Last reply
                  0
                  • E El Corazon

                    Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?

                    _________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)

                    J Offline
                    J Offline
                    JudyL_MD
                    wrote on last edited by
                    #41

                    I only use two-stage construction when initialization can fail for a multitude of reasons AND the code creating the object needs to know which on the many reasons caused the failure. Constructors can't return values, so all you know is that it failed to construct. I use two-stage quite often when the class wraps some kind of communication. The class is not fully up and running until the comms are active, and I need to know why comms aren't active as the class starts up. Judy

                    L 1 Reply Last reply
                    0
                    • J Jorgen Sigvardsson

                      IMO, it boils down to this: 1) If the object is a first class entity - i.e., not a handle - then do initialization and finalization in constructor and destructor 2) If the object is a simple handle (such as a CWnd derivative), then there are two life lines - the handle object itself and whatever it's handling. Then I use init()/cleanup() to handle the life line of the handled object. My reason for 2) is that the destruction of handled object may fail - something I don't want to deal with in a destructor (if you say exception, then you've not only shot yourself in the foot, but you've also blown your brains out). Also, I might want to be able to share the handled object between handles, or I might just want to transfer the responsibility of it elsewhere. Note that this isn't something I've learned in school. I've picked it up as I go... :)

                      -- Raaaaaaaaaaaaaaaaaaaaa!

                      P Offline
                      P Offline
                      peterchen
                      wrote on last edited by
                      #42

                      Very good criterion to separate these. HOWEVER, (muhahahah!)

                      Joergen Sigvardsson wrote:

                      the destruction of handled object may fail - something I don't want to deal with in a destructor

                      however, if the caller doesn't call Close() - because he's lazy or an exception got into the way, you still have to deal with that.

                      Joergen Sigvardsson wrote:

                      Also, I might want to be able to share the handled object between handles, or I might just want to transfer the responsibility of it elsewhere.

                      But Joergen! That's why there is shared_ptr!


                      We are a big screwed up dysfunctional psychotic happy family - some more screwed up, others more happy, but everybody's psychotic joint venture definition of CP
                      My first real C# project | Linkify!|FoldWithUs! | sighist

                      J B 2 Replies Last reply
                      0
                      • P peterchen

                        Very good criterion to separate these. HOWEVER, (muhahahah!)

                        Joergen Sigvardsson wrote:

                        the destruction of handled object may fail - something I don't want to deal with in a destructor

                        however, if the caller doesn't call Close() - because he's lazy or an exception got into the way, you still have to deal with that.

                        Joergen Sigvardsson wrote:

                        Also, I might want to be able to share the handled object between handles, or I might just want to transfer the responsibility of it elsewhere.

                        But Joergen! That's why there is shared_ptr!


                        We are a big screwed up dysfunctional psychotic happy family - some more screwed up, others more happy, but everybody's psychotic joint venture definition of CP
                        My first real C# project | Linkify!|FoldWithUs! | sighist

                        J Offline
                        J Offline
                        Jorgen Sigvardsson
                        wrote on last edited by
                        #43

                        peterchen wrote:

                        however, if the caller doesn't call Close() - because he's lazy or an exception got into the way, you still have to deal with that.

                        Yes, that's where RIAA comes into play. :)

                        peterchen wrote:

                        But Joergen! That's why there is shared_ptr!

                        Well, that works wonders, if it's a pointer to a handle. That is not always the case. MFC and ATL/WTL objects come to mind.

                        -- Larva-Tested, Pupa-Approved

                        J 1 Reply Last reply
                        0
                        • J JudyL_MD

                          I only use two-stage construction when initialization can fail for a multitude of reasons AND the code creating the object needs to know which on the many reasons caused the failure. Constructors can't return values, so all you know is that it failed to construct. I use two-stage quite often when the class wraps some kind of communication. The class is not fully up and running until the comms are active, and I need to know why comms aren't active as the class starts up. Judy

                          L Offline
                          L Offline
                          Lost User
                          wrote on last edited by
                          #44

                          But constructors can throw exceptions... but I also appreciate that exceptions are not everyones cup of tea. :)


                          Kicking squealing Gucci little piggy.
                          The Rob Blog

                          1 Reply Last reply
                          0
                          • L Leslie Sanford

                            Dario Solera wrote:

                            Dispose/Finalize is invoked automatically (but not necessarily immediately) when the instance goes out of scope.

                            I don't think Dispose is invoked automatically. I know the finalizer is, but by the time it's invoked, you can't count on any of the references in your object as still being valid. They may have already been collected. You can release unmanaged resources (which is important), but that's about it.

                            D Offline
                            D Offline
                            Daniel Grunwald
                            wrote on last edited by
                            #45

                            You're references will not be collected, they just might have been finalized if they also have a finalizer. You can even revive references from finalizers. But you should never call another object's Dispose() method from a finalizer - if that object needs to do cleanup, it should have its own finalizer.

                            L 1 Reply Last reply
                            0
                            • M Miszou

                              Nemanja Trifunovic wrote:

                              constructors can't return values to tell us if something went wrong

                              I've recently started using a library that makes all constructors inaccessible, and all objects must be created by a overloads of a static Create method on the object. eg:

                              class MyClass
                              {
                                  private MyClass() {}
                              
                                  public static MyClass Create()
                                  {
                                      return new MyClass();
                                  }
                              }
                              

                              I first thought that this was because constructors could not return failure codes, but as I type this, I realize that a static Create method with a specific return type can't return a status code either! Then I thought it was for serializing the object or something of that nature, but with reflection (in .NET), you can call a constructor as easily as any other method. My final thoughts on this, are that the Create method does not have to return a specific instance, while a constructor does. This means that in a complex hierarchy, you can be given a descendent object instead of the object you asked actually asked for, depending on how the Create method works. A highly contrived example:

                              class ClassA
                              {
                                  private ClassA() {}
                              
                                  public static ClassA Create( int x )
                                  {
                                      if ( x < 0 )
                                          return new ClassA();
                                      else
                                          return ClassB.Create();
                                  }
                              }
                              
                              class ClassB : ClassA
                              {
                                  private ClassB() {}
                              
                                  public static ClassB()
                                  {
                                      return new ClassB();
                                  }
                              }
                              
                              static void main()
                              {
                                  ClassA myClass = ClassA.Create( 3 ); // Will really create a ClassB
                              }
                              

                              Is this what it's used for? Or am I heading into La-La Land with this line of thinking?


                              Sunrise Wallpaper Project | The StartPage Randomizer | A Random Web Page

                              D Offline
                              D Offline
                              Daniel Grunwald
                              wrote on last edited by
                              #46

                              I use static Create() methods only when creating an instance has a side-effect, e.g. opening a TCP connection. If the Create() method can return derived classes, I would put it in a factory class and not in the base class.

                              M 1 Reply Last reply
                              0
                              • D Daniel Grunwald

                                I use static Create() methods only when creating an instance has a side-effect, e.g. opening a TCP connection. If the Create() method can return derived classes, I would put it in a factory class and not in the base class.

                                M Offline
                                M Offline
                                Miszou
                                wrote on last edited by
                                #47

                                Daniel Grunwald wrote:

                                If the Create() method can return derived classes, I would put it in a factory class and not in the base class

                                I agree. Like I said, it was a terrible contrived example, and after I posted it I realized how bad it actually was! Having a base class create derived classes would be a complete WTF... :-O


                                Sunrise Wallpaper Project | The StartPage Randomizer | A Random Web Page

                                D 1 Reply Last reply
                                0
                                • D Daniel Grunwald

                                  You're references will not be collected, they just might have been finalized if they also have a finalizer. You can even revive references from finalizers. But you should never call another object's Dispose() method from a finalizer - if that object needs to do cleanup, it should have its own finalizer.

                                  L Offline
                                  L Offline
                                  Leslie Sanford
                                  wrote on last edited by
                                  #48

                                  Daniel Grunwald wrote:

                                  You're references will not be collected, they just might have been finalized if they also have a finalizer. You can even revive references from finalizers. But you should never call another object's Dispose() method from a finalizer - if that object needs to do cleanup, it should have its own finalizer

                                  Thanks for the clarification. I appreciate it.

                                  1 Reply Last reply
                                  0
                                  • E El Corazon

                                    Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?

                                    _________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)

                                    C Offline
                                    C Offline
                                    Chris Bowen
                                    wrote on last edited by
                                    #49

                                    I have not previously encountered this approach (and I have been coding professionally for nearly fourteen years). I disagree with the separate init() method approach for a number of reasons: a.) Expectations (one should follow convention) - most frameworks will initialise objects through the constructor, and users of your code (who can even be your co-workers or your future co-workers) are likely to expect that too. They will easily do something wrong if the class usage semantics are unconventional. b.) You create an additional source of failure (read source of bugs), because nother method must be called before the object can be used. Omission of this call can create a hard to track down bug. Why create this possibility? c.) Error checking. You have created an additional state for your objects to exist in. You have made it possible to use your class without it being initialised, and so you ALWAYS have to ensure that when a public method is called the object has been correctly initialised. Usually you would only have to place guards on the methods that are intended to modify the object's contents in order to ensure that the contents are valid. If your object can be inherited from (this is C++ so unless you only construct objects through a factory method, your class can be inherited from), then you have to place guards in the protected methods as well. Ugly! d.) Calling init() (or whatever you call it) multiple times becomes possible but probably does not make sense. If you need this capability for the object, then you are either reset()ing the object, or you need to construct a new one. e.) Copy constructors - when copy semantics are needed for a class, the constructor has to create a fully initialised object. This breaks the paradigm. f.) C++ will chain the calling of constructors. The compiler will tell you if you get the chaining wrong. You will have to implement this manually if you use an init() method, and there will be no compile-time errors to tell you that you got it wrong. It's even more error prone when you are using multiple inheritance. You have once again created a source of potentially hard-to-find bugs. Why? g.) Performance - initialising attributes within a constructor (especially within the member initialisation list) is more efficient than initialising them from a separate method. If performance is any concern, you will almost certainly want the constructor to do it all. h.) If you absolutely must perform initialisation in a separate method, make the method

                                    1 Reply Last reply
                                    0
                                    • E El Corazon

                                      Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?

                                      _________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)

                                      Y Offline
                                      Y Offline
                                      Yortw
                                      wrote on last edited by
                                      #50

                                      Generally I think it's best to have the constructor/destructor perform the intilisation/clean up. Breaking the code out into an init procedure which is called from the constructor(s) can be useful for sharing similar code between constructors but otherwise it's a personal preference thing... However, there are times when init/cleanup methods are required. One example is when you want to support some kind of object pooling mechanism, in which case you'll want to be able to clean up the class without it be 'finalized' and you'll want to be able to re-initialize it when it's retreive back out of the pool - at which point the constructor is useless since the object has already been created. If initialisation is expensive, then you may also want to be able to create X number of classes in the pool (on startup for example) and allow the initialization to take place 'lazily' after the fact. Also, the 'clean up' style methods may be needed depending on what language you're working in. In something like C# where there is no deterministic finalization you need an explicit clean up method on some objects to allow immediate release of unmanaged resources (hence the IDisposable interface, which is really just a system supported way of implementing a clean up method). In VB6, circular references between classes could be a problem, in which case a clean up method would sometimes be needed to release at least one set of references so memory wasn't leaked and the classes did actually get 'finalized' eventually. I can't think of another instance when 'init' style methods are useful, except for the object pooling, although that might just be lack of imagination on my part :) Basically, I think it depends on that particular patterns and architecture you're using, but for mmost classes the constructors/destrutors are the right place for init/cleanup code.

                                      U M 2 Replies Last reply
                                      0
                                      • N Nemanja Trifunovic

                                        El Corazon wrote:

                                        Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved.

                                        That idiom is called "two-phase construction" and was widely used before exceptions were available for C++. For instance, MFC uses it all the time simply because VC++ didn't support exceptions at the time that MFC was designed. In general, today most experts including Stroustrup recommend avoiding two-phase construction, but some people don't use exceptions for one reason or another and they really have little choice: constructors can't return values to tell us if something went wrong :)


                                        Programming Blog utf8-cpp

                                        J Offline
                                        J Offline
                                        Jonas Hammarberg
                                        wrote on last edited by
                                        #51

                                        I have two solutions for those classes (and of course, no other human being has ever thought about this extremely clever solution:->). - a status function that checks invariants (mostly as simple as a fail or success flag) -- is_ok() - a static factory, mostly returning a std::pair (or just object*). This requires that one hides the c'tors (except assignment and copy -- falling back to is_ok()) auto_ptr f(new Foo(bar)); if(f->is_ok())... or auto_ptr f(Foo::create(bar)); if(f/* && f->is_ok()*/)... or pair> r(Foo::create(bar)); if(r->first == BAD_DOG) //drooled on the ham...:omg:

                                        1 Reply Last reply
                                        0
                                        • E El Corazon

                                          Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?

                                          _________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)

                                          N Offline
                                          N Offline
                                          Neil P Truick
                                          wrote on last edited by
                                          #52

                                          In my experience, I've always wanted my classes ready to use from the time they are created. If I want a null instance, I create a null constructor. If I want the fields populated, I create an overloaded constructor that does that. I used to build separate routines that performed similar functions as yours, but tracking what did what became too much of a maintenance overhead. Once I began overloading the constructors, management became a lot easier. I'm not saying that I didn't refactor, because I did and I do. If I had redundant initialization code, I pulled them out into their own methods. But, I do not automatically pull out initialization just for the sake of pulling it out, because it's "easier to test," which, by the way, really doesn't make it any easier. It just creates additional, unnecessary function points... My $0.02...

                                          1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups