开发者

when should I use the new operator in C++

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

I could initialize it in the followings 2 ways:

  1. Money a(3,15)开发者_Python百科;
  2. Money *b=new Money(3,15);

My question is when should I use (1) and when should I use (2)


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.


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


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.


This is a much more complex question than it looks. The simple answer is

1) When you want to stack storage and scope bound resource management, when the scope is left the destructor on this object will be called and storage on the stack will be popped.

Be careful not to pass a pointer to one of these scope-bound objects up the call stack (returning, output parameters), this is an easy way to segfault.

2) When you want the object allocated on the free-store, this pointer must be deleted or a memory leak will occur.

Take a look at shared_ptr, scoped_ptr, auto_ptr, et al. for some alternatives that make #2 act in some ways like #1.

Also, take a look at this question for some pointers on memory management in C++.


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.


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;
}


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.


In general, you would use form 1 when the object has a limited life span (within the context of a block) and use form 2 when the object must survive the block it is declared in. Let me give a couple of examples:

int someFunc() {
    Money a(3,15);
    ...
} // At this point, Money is destroyed and memory is freed.

Alternatively, if you want to have the objects survive the function, you would use new as follows:

Money *someOtherFunc() {
    Money *a = new Money(3,15);
    ....
    return a;
} // we have to return a here or delete it before the return or we leak that memory.

Hope this helps.


You should use option two when you want a pointer to an object, and option one when you want a value.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜