2

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);
  2. Money *b=new Money(3,15);

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

gideon
  • 19,329
  • 11
  • 72
  • 113
Robert Dennis
  • 335
  • 2
  • 4
  • 8

9 Answers9

8

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.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • There are quite a few times when you have to create a pointer to an object that's lifetime will be limited to the scope you are currently in...otherwise scoped_ptr would be pretty useless. – Edward Strange Feb 22 '11 at 19:19
  • `scoped_ptr` is only somewhat tied to scope. – Thomas Edleson Feb 22 '11 at 19:42
  • @Thomas - you'd have to expand on that before I could even understand what you mean to assert. – Edward Strange Feb 22 '11 at 19:55
  • @Crazy: `scoped_ptr` is used (for example) for capturing the return value from a function like a factory, in which case the *callee* is in the position of creating an object that isn't "limited to the scope you are currently in". If you merely need a pointer to an object whose lifetime is limited to the current scope, you can take a pointer to an automatic variable. – Steve Jessop Feb 22 '11 at 20:21
  • @Crazy Eddie: I could hardly have said it better myself. IMO, `scoped_ptr` *is* severely overused, but "pretty useless". – Jerry Coffin Feb 22 '11 at 20:21
  • @Steve - I don't see how that answers the question or has anything to do with anything. Really, I don't. Not trying to be obnoxious. Where you trying to explain why scoped_ptr is not tied to scope or something else? – Edward Strange Feb 22 '11 at 20:23
  • @Crazy Eddie: I was trying to explain why `scoped_ptr` has nothing to do with "creating a pointer to an object that's lifetime will be limited to the scope you are currently in". That's not what it's for. It's used when *storing* a pointer to such an object, but it's only needed for that purpose when the object was actually created in a smaller scope. If I had to, I'd guess that Thomas says "only somewhat tied" because `scoped_ptr` has a `reset()` function, so the object can have shorter lifetime than the scope. But that is just a guess and I wasn't commenting on what he said. – Steve Jessop Feb 22 '11 at 20:27
  • @Crazy Eddie: the situation can be summarized pretty simply: I'd say at least 80% of the times I've seen `scope_ptr` used, it was because the author refused to trust [N]RVO. Removing the `scoped_ptr` made the code simpler and faster in nearly every case. In fairness, there *are* cases where it's useful, but IME, they really are pretty rare. – Jerry Coffin Feb 22 '11 at 20:31
  • @Steve - my point is that there are a lot more "have to" times than just creating an object that outlives current scope. I don't see how anything said in response so far applies to that, including what you've said. That's why I'm confused. There IS a use for scoped_ptr...holding an object you had to create via new (probably through a factory function) but isn't going anywhere. These cases are even more important, maybe even more frequent, than extending lifetime past scope. – Edward Strange Feb 22 '11 at 20:34
  • @Jerry - so scoped_ptr is useless because stupid people do stupid things? I simply don't agree. Scoped_ptr is very useful whenever you are using an abstraction within a defined scope. It's better than alternatives because it enforces scoping so that you don't accidentally violate it, trying to copy an object that contains one without a proper copy constructor for example. I've seen a lot of people misuse a lot of constructs...I don't take it out on the construct. – Edward Strange Feb 22 '11 at 20:37
  • @Crazy Eddie: not, it's [nearly] useless, because by the time you get rid of the times it's being put to questionable purposes, you have nearly nothing left. – Jerry Coffin Feb 22 '11 at 20:45
6

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

Jordan
  • 4,928
  • 4
  • 26
  • 39
  • I notice that our both answers are nearly identical but I swear I did not notice yours before posting mine. – Benoit Feb 22 '11 at 19:13
3
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.

  • -1: Never return a pointer. Pointer have no ownership semantics. Always return a smart pointer. – Martin York Feb 22 '11 at 19:19
  • @Martin - wrong. Factory code should not enforce ownership semantics unless those semantics are integral to the type being created, and this is rare. Allow the client code to decide. Factory code like the post you're complaining about is a very valid place to use pointers. +1 to counter your -. – Edward Strange Feb 22 '11 at 19:41
  • Downvoting for returning a pointer in this example is harsh, to say the least. – Thomas Edleson Feb 22 '11 at 19:45
  • @Crazy Eddie: Factory code like the above *already* implies ownership: it returns an owning pointer. Using a smart pointer puts that implicit contract into the type system. It also implies how it should be deallocated: if I return an auto_ptr, you know a delete-expression is required. – Thomas Edleson Feb 22 '11 at 19:48
  • @Thomas - no kidding on the harshness, especially with the kudos from the op. As to the rest.... pointers don't own anything, they just point. You can have several pointers to the same object, but there should be only one owner. So just saying that the factory already implies ownership because it returns a pointer doesn't seem reasonable to me. At the very least you'd better return a convertible smart pointer so the ownership semantics can be changed. – Edward Strange Feb 22 '11 at 19:53
  • @Crazy Eddie: The *type* "pointer to T" doesn't itself say anything about ownership, but initialize() above is definitely returning an owning pointer. Yes, you should return a flexible smart pointer, such as auto_ptr for single objects allocated with new. This makes the caller use release(), safe implicit conversion (e.g. boost::shared_ptr has an implicit auto_ptr ctor), or similar. – Thomas Edleson Feb 22 '11 at 19:58
  • 2
    @Crazy Eddie: Completely disagree. If the factory wants to own the object return a reference. If it wants to give up ownership return an auto_ptr. There is **NEVER** a good reason to return a pointer (OK there are reasons but none that are simple). – Martin York Feb 22 '11 at 20:38
2

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++.

Community
  • 1
  • 1
joshperry
  • 41,167
  • 16
  • 88
  • 103
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;
}
Martin York
  • 257,169
  • 86
  • 333
  • 562
1

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.

JohnMcG
  • 8,709
  • 6
  • 42
  • 49
0

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.

Benoit
  • 76,634
  • 23
  • 210
  • 236
0

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.

Lou
  • 1,955
  • 14
  • 16
-3

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

Edward Strange
  • 40,307
  • 7
  • 73
  • 125