How much work should be done in a constructor?

后端 未结 18 970
离开以前
离开以前 2020-11-27 17:40

Should operations that could take some time be performed in a constructor or should the object be constructed and then initialised later.

For example when constructi

相关标签:
18条回答
  • 2020-11-27 18:00

    It depends (typical CS answer). If you are constructing objects at startup for a long-running program, then there is no problem with doing a lot of work in constructors. If this is part of a GUI where fast response is expected, it might not be appropriate. As always, the best answer is to try it the simplest way first, profile, and optimize from there.

    For this specific case, you can do lazy construction of the sub-directory objects. Only create entries for the names of the top level directories. If they are accessed, then load the contents of that directory. Do this again as the user expolres the directory structure.

    0 讨论(0)
  • 2020-11-27 18:00

    For the sake of code maintenance, testing, and debugging I try to avoid putting any logic in constructors. If you prefer to have logic execute from a constructor then it is helpful to put the logic in a method such as init() and call init() from the constructor. If you plan on developing unit tests you should avoid putting any logic in a constructor since it may be difficult to test different cases. I think the previous comments already address this, but... if your application is interactive then you should avoid having a single call that leads to a noticeable performance hit. If your application is non-interactive (ex: nightly batch job) then a single performance hit isn't as big a deal.

    0 讨论(0)
  • 2020-11-27 18:00

    Excellent question: the example you gave where a 'Directory' object has references to other 'Directory' objects is also a great example.

    For this specific case I would move the code to build up subordinate objects out of the constructor (or maybe do the first level [immediate children] as another post here recommends), and have a separate 'initialize' or 'build' mechanism).

    There is another potential issue otherwise - beyond just performance - that is memory-footprint: If you end up making very deep recursive calls, you will likely end up with memory problems as well [since the stack will be keeping copies of all the local variables until the recursion finishes].

    0 讨论(0)
  • 2020-11-27 18:03

    I would agree that long running constructors are not inherently bad. But I would argue that thy are almost always the wrong thing to do. My advice is similar to that from Hugo, Rich, and Litb:

    1. keep the work you do in constructors to a minimum - keep the focused on initializing state.
    2. Don't throw from constructors unless you cannot avoid it. I try to only throw std::bad_alloc.
    3. Don't call OS or Library APIs unless you know what they do - most can block. They will run quickly on your dev box and test machines, but in the field they can be blocked for long periods of time as the system is busy doing something else.
    4. Never, ever do I/O in a constructor - of any kind. I/O is commonly subject to all kinds of very long latencies (100's of milliseconds to seconds). I/O includes
      • Disk I/O
      • Anything that uses the network (even indirectly) Remember most resources can be off box.

    I/O problem example: Many hard disks have a problem where they get into a state where they do not service reads or writes for 100's or even thousands of milliseconds. The first and generation solid state drives do this often. The user has now way of knowing that your program jus hung for a bit - they just think it is your buggy software.

    Of course, the evilness of a long running constructor is dependent on two things:

    1. What 'long' means
    2. The how often in a given period objects with the 'long' constructors are constructed.

    Now, if 'long' is simply a few 100 extra clock cycles of work, then its not really long. But a constructor is getting into the 100's of microsecond range the I suggest it is pretty long. Of course, if you are only instantiating one of these, or instantiating them rarely (say one every few seconds) then you are not likely to see problms due to a duration in this range.

    Frequency is an important factor, a 500 us ctor isn't a problem if you are only building a few of them: but creating a million of them would pose a significant performance problem.

    Lets talk about your example: populating a tree of directory objects inside "class Directory" object. (note, I'm going to assume this is a program with a graphical UI). Here, your CTOR duration isn't dependent on the code you write - its defendant on the time it takes to enumerate an arbitrarily large directory tree. This is bad enough on local hard drive. Its even more problematic on remote (networked) resurce.

    Now, imagine doing this on your user interface thread - your UI will stop dead in its tracks for seconds, 10's of seconds or potential even minutes. In Windows we call this a UI hang. They are bad bad bad (yes we have them... yes we work hard to eliminate them).

    UI Hangs are something that can make people really hate your software.

    The right thing to do here is simply initialize your directory objects. Build your directory tree in a loop that is can be canceled and keeps your UI in a responsive state ( the cancel button should always works)

    0 讨论(0)
  • 2020-11-27 18:06

    Make sure the ctor does nothing that could throw an exception.

    0 讨论(0)
  • 2020-11-27 18:07

    If something can be done outside a constructor, avoid doing it inside. Later, when you know your class is otherwise well-behaved, you might risk doing it inside.

    0 讨论(0)
提交回复
热议问题