C++ idiom to avoid memory leaks?

后端 未结 11 1603
被撕碎了的回忆
被撕碎了的回忆 2021-01-28 21:01

In the following code, there is a memory leak if Info::addPart1() is called multiple times by accident:

typedef struct
{
}part1;

typedef struct
{
}         


        
相关标签:
11条回答
  • 2021-01-28 21:18

    You should read about the smart pointer idiom and about RAII. I suggest taking a look into the new technical report (TR1).
    Take a good look here and here.
    Also take a look at boost's smart pointers.
    I recommend loki-lib's SmartPtr or StrongPtr classes.

    0 讨论(0)
  • 2021-01-28 21:19

    Bear with me here...

    In the distant past, programmers used constructs like "jump" and "goto" for flow control. Eventually common patterns emerged and constructs like for, do/while, function call and try/catch emerged, and the spaghetti was tamed. Those named constructs give a lot more information about intent than a generic goto, where you have to examine the rest of the code for context to understand what it's doing. In the unlikely event you see a goto in modern code by a competent coder, you know something pretty unusual is going on.

    In my opinion, "delete" is the "goto" of memory management. There are enough smart pointer and container classes available to the modern developer that there's very little reason for most code to contain a single explicit delete (other than in the smart pointer implementations of course). When you see a plain "delete" you get no information about intent; when you see a scoped_ptr/auto_ptr/shared_ptr/ptr_container you get a lot more.

    ie the idiom should be to aspire to write delete-free code by using appropriate smart pointer types (as recommended by just about every other answer here).

    Update 2013-01-27: I note Herb Sutter's excellent talk on C++11 includes some similar sentiments re delete free code.

    0 讨论(0)
  • 2021-01-28 21:19

    I agree with the group that you should use some kind of smart pointer.

    If you do decide to continue with bare pointers, be aware that your class above does not have a copy constructor defined by you. Therefore, the C++ compiler has defined one for you that will just do a simple copy of all the pointers; which will lead to a double delete. You'll need to define your own copy constructor (or at least create a stub private copy constructor if you don't think you need a copy constructor).

    Info(const Info &rhs)
    {
      _ptr1 = new part1[rhs._ptr1];
      _ptr2 = new part2[rhs._ptr2];
    }
    

    You will have a similar problem with the default assignment operator.

    If you choose the correct smart pointer, these problems will go away. :)

    0 讨论(0)
  • 2021-01-28 21:23

    Your suggested fix will work (though of course you're still at risk for a memory leak if addPart2() is called twice). A much safer approach is to use scoped_ptr from the Boost library collection (www.boost.org), which is a container that acts like a pointer, but guarantees that its target is deleted when the container is destroyed. Your revised class would then look like

    class Info
    {
        private:
        boost::scoped_ptr<part1> _ptr1;
        boost::scoped_ptr<part2> _ptr2;    
    
        public:
        Info() {}  // scoped_ptrs default to null
    
        // You no longer need an explicit destructor- the implicit destructor
        // works because the scoped_ptr destructor handles deletion
    
        addPart1()
        {
          _ptr1.reset(new part1);
        }
    
        addPart2()
        {
          _ptr2.reset(new part2);         
        }   
    };
    

    As a general principle, it's a good idea to avoid writing code that requires you to explicitly delete pointers. Instead, try to use containers that do it automatically at the appropriate time. Boost is a good resource for this kind of thing.

    All this assumes you have a reason ptr1_ and ptr2_ need to be pointers. If not, it's much better to make them ordinary objects; then you get memory management for free.

    0 讨论(0)
  • 2021-01-28 21:25

    If you want it to have a lazy behavior you might consider this:

    addPart1()
    {
        if(_ptr1 == NULL) {
            _ptr1 = new part1;
        }
    }
    

    The way you suggested is also an alternative depending how you want it to behave. But other people have suggested better ways to do it, but as we really don't know why you made it this way and how the surrounding code works ...

    0 讨论(0)
  • Use construction is initialization instead.

    class Info
    {
        private:
        part1* _ptr1;
        part2* _ptr2;    
    
        public:
        Info() : _ptr1(new part1), _ptr2(new part2)
        {
        }
    
        ~Info()
        {
          delete _ptr1; 
          delete _ptr2;
        }
    };
    

    But in this case you might as well create the parts on the stack, so no new and delete is required.

    class Info
    {
        private:
        part1 _part1;
        part2 _part2;    
    
        public:
        Info()
        {
        }
    
        ~Info()
        {
        }
    };
    

    But I guess you want the pointers to be lazy created, then I wouldn't suggest to create public class methods that takes care of the initializations. This should be handled internally in the class, when the class need to allocate them.

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