when should I use the new operator in C++

后端 未结 9 1916
有刺的猬
有刺的猬 2020-12-21 11:47

Say I have a class called Money which has parameters Dollars and Cents

I could initialize it in the followings 2 ways:

相关标签:
9条回答
  • 2020-12-21 12:02

    Form 1 is simplest; use it when you can.

    Form 2 buys you the following things:

    • Ability to determine at run-time whether to create the object at all.
    • Ability to determine at run-time how big an array of these objects to create
    • Ability to determine at run-time what subclass to create (e.g. Should Money* b point to GoodMoney or BadMoney
    • Ability to determine at run-time the lifecycle of the object

    Form 2 introduces the possibility or resource leaks, since objects created with new must ultimately be destroyed with delete. As others have noted, this problem can be eliminated or mitigated by using smart pointers.

    In short, use Form 2 when you need one of the things listed above, and then put it in a smart pointer; otherwise use Form 1.

    0 讨论(0)
  • 2020-12-21 12:02

    Well technically would prefer you never did (2) directly but prefered the use of a smart pointer:

    std::auto_ptr<Money> b(new Money(3,15));  // auto_ptr is just an example of a smart pointer
    

    But the overall question remains.
    Use (1) when the lifespan of the object does not exceed the function or object that is using it. Use (2) when the lifespan of the object extends for longer than you can predict at compile time.

    1. Is refereed to as a automatic storage duration object. This means that it is automatically created and destroyed (important bit) by code that is generated by the compiler.

    2. Is referred to as dynamic storage duration object. This means that it is your responsibility to both manually create and destroy the object. Destroying the object requires that we maintain the concept of ownership associated with the object and only allow the owner to destroy it (otherwise we get multiple sources trying to destroy the object). To aid in the ownership tracking we introduce smart pointers that own the pointer. It then becomes the responsibility of the smart pointer to do the actual work of destroying the object. Which makes building classes and functions with pointers a lot easier.

    If your object is cheap to create an copy(which it looks like it is). Then you shouls hardly ever need to create the object dynamically. Passing an object to a function or returning a result can all be done quite normally:

    Money CalcInterest(Money const& m, double interest)
    {
        Money result(m.doallas * interest, m.cent * interest);
        return result; // Return a copy quite happily.
    }
    

    If you were building a dynamic expression is then you can hold the pointers using smart pointers.

    struct Expression
    {
        char   op;
        std::auto_ptr<Money>   lhs;
        std::auto_ptr<Money>   rhs;
    };
    
    std::auto_ptr<Expression> getExpressionFromUserInput()
    {
         std::auto_ptr<Expression>  result(new Expressions(/* etc */);
         return result;
    }
    
    0 讨论(0)
  • 2020-12-21 12:09

    The first one creates a Money object on the stack, its lifespan is within the scope of when it was created. Meaning when you hit a } it goes out of scope and the memory is returned. Use this when you want to create an object within one function.

    The second one creates a Money object on the heap, its lifespan is as long as you want it to be, namely until you delete it. Use this when you want your object to be passed around to different functions

    0 讨论(0)
  • 2020-12-21 12:10

    Use 1 when you can, 2 when you have to. The "when you have to" basically translates to "when you're creating an object that whose lifetime is not/cannot be tied to "scope" -- i.e., it must remain in existence after the function that created it exits. You generally want to avoid this if you can though, such as by returning a copy of the object in question, instead of making that object (itself) last after the function returns.

    Past that, there are (unfortunately) no really hard and fast guidelines to follow that assure you're doing things as well as possible.

    0 讨论(0)
  • 2020-12-21 12:23
    Money a(3,15);
    

    Allocates an Money object in the local scope.

    Money* b=new Money(3,15);
    

    Allocates a pointer-variable to the local scope, and makes the pointer "point" to a Money object that resides in the free store (assuming the allocation completed successfully, otherwise an std::bad_alloc() is thrown)

    Example 1 :

    Assume next scenario:

    Money * b = initialize();
    

    where

    Money* initialize()
    {
          Money x(2 , 15);
          return &x;
    }
    

    This will fail because after initialize() reaches the end of execution x is destroyed, and now b points to a location that is invalid to use and invokes Undefined Behaviour if you do used it. so instead you should allocate it with a pointer

    Money* initialize()
    {
          return new Money(2,15);
    }
    

    The free-store is also used when you want to store and use arrays of great size.

    There is a difference between the two as you noticed on the example, and that is that in the local scope x you do not need to delete the object. But when using new you will have to manually do a delete x;. Otherwise a memory leak (memory space is occupied without ever going to be used again, hence eating memory) is occurring.

    See Martin York's answer for deeper knowledge beyond this post.

    0 讨论(0)
  • 2020-12-21 12:25

    It is totally different.

    1. You have an object which is constructed on the stack. It will have a scope of life that lasts for a code block.

    2. You have an object initialized at some memory address allocated in the heap. It will not be destroyed until you call delete b.

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