2

I am still new to C++. I have found that you can instantiate an instance in C++ with two different ways:

// First way
Foo foo;
foo.do_something();

// Second way
Baz *baz = new Baz();
baz->do_something();

And with both I don't see big difference and can access the attributes. Which is the preferred way in C++? Or if the question is not relevant, when do we use which and what is the difference between the two?

Thank you for your help.

Joshua Partogi
  • 16,167
  • 14
  • 53
  • 75

5 Answers5

4

The question is not relevant: there's no preferred way, those just do different things.

C++ both has value and reference semantics. When a function asks for a value, it means you'll pass it a copy of your whole object. When it asks for a reference (or a pointer), you'll only pass it the memory address of that object. Both semantics are convertible, that is, if you get a value, you can get a reference or a pointer to it and then use it, and when you get a reference you can get its value and use it. Take this example:

void foo(int bar) { bar = 4; }
void foo(int* bar) { *bar = 4; }
void test()
{
    int someNumber = 3;
    foo(someNumber); // calls foo(int)
    std::cout << someNumber << std::endl; 
    // printed 3: someNumber was not modified because of value semantics,
    // as we passed a copy of someNumber to foo, changes were not repercuted
    // to our local version

    foo(&someNumber); // calls foo(int*)
    std::cout << someNumber << std::endl;
    // printed 4: someNumber was modified, because passing a pointer lets people
    // change the pointed value
}

It is a very, very common thing to create a reference to a value (i.e. get the pointer of a value), because references are very useful, especially for complex types, where passing a reference notably avoids a possibly costly copy operation.

Now, the instantiation way you'll use depends on what you want to achieve. The first way you've shown uses automatic storage; the second uses the heap.

The main difference is that objects on automatic storage are destroyed with the scope in which they existed (a scope being roughly defined as a pair of matching curly braces). This means that you must not ever return a reference to an object allocated on automatic storage from a regular function, because by the time your function returns, the object will have been destroyed and its memory space may be reused for anything at any later point by your program. (There are also performance benefits for objects allocated on automatic storage because your OS doesn't have to look up a place where it might put your new object.)

Objects on the heap, on the other hand, continue to exist until they are explicitly deleted by a delete statement. There is an OS- and platform-dependant performance overhead to this, since your OS needs to look up your program's memory to find a large enough unoccupied place to create your object at. Since C++ is not garbage-collected, you must instruct your program when it is the time to delete an object on the heap. Failure to do so leads to leaks: objects on the heap that are no longer referenced by any variable, but were not explicitly deleted and therefore will exist until your program exits.

So it's a matter of tradeoff. Either you accept that your values can't outlive your functions, or you accept that you must explicitly delete it yourself at some point. Other than that, both ways of allocating objects are valid and work as expected.

For further reference, automatic storage means that the object is allocated wherever its parent scope was. For instance, if you have a class Foo that contains a std::string, the std::string will exist wherever you allocate your Foo object.

class Foo
{
public:
    // in this context, automatic storage refers to wherever Foo will be allocated
    std::string a;
};

int foo()
{
    // in this context, automatic storage refers to your program's stack
    Foo bar; // 'bar' is on the stack, so 'a' is on the stack
    Foo* baz = new Foo; // 'baz' is on the heap, so 'a' is on the heap too
    // but still, in both cases 'a' will be deleted once the holding object
    // is destroyed
}

As stated above, you cannot directly leak objects that reside on automatic storage, but you cannot use them once the scope in which they were created is destroyed. For instance:

int* foo()
{
    int a; // cannot be leaked: automatically managed by the function scope
    return &a; // BAD: a doesn't exist anymore
}

int* foo()
{
    int* a = new int; // can be leaked
    return a; // NOT AS BAD: now the pointer points to somewhere valid,
              // but you eventually need to call `delete a` to release the memory
}
zneak
  • 134,922
  • 42
  • 253
  • 328
  • (Though in real code please don't do the second example -- if you must do something like this use a `std::auto_ptr` to signify to the caller that they must `delete` the variable in question.) – Billy ONeal Mar 16 '11 at 04:10
2

The first way -- "allocating on the stack" -- is generally faster and preferred much of the time. The constructed object is destroyed when the function returns. This is both a blessing -- no memory leaks! -- and a curse, because you can't create an object that lives for a longer time.

The second way -- "allocating on the heap" is slower, and you have to manually delete the objects at some point. But it has the advantage that the objects can live on until you delete them.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
  • 2
    I don't like this explanation. Perhaps you didn't mean it this way, but to me it implies that if you need to create a new object and return it from a function, that you should use `new` and return the pointer. But generally, that's *not* what you should do. You should just return the object and let a copy happen(although, in most cases, it will be elided or moved) – Benjamin Lindley Mar 16 '11 at 02:51
  • Benjamin is absolutely right; when you return an object "by value" from a C++ function, a copy of the stack object is made, and that copy can live on, *and* this is indeed a very common thing to do. I spend less time programming in C++ than in languages like Java where identity semantics are used a lot, and I have to confess that all that copying makes me squeamish. – Ernest Friedman-Hill Mar 16 '11 at 03:00
0

The first way allocates the object on the stack (though the class itself may have heap-allocated members). The second way allocates the object on the heap, and must be explicitly delete'd later.

It's not like in languages like Java or C# where objects are always heap-allocated.

wkl
  • 77,184
  • 16
  • 165
  • 176
  • Thanks for your explanation. I came from Java background, that is why I was a bit confused with this. – Joshua Partogi Mar 16 '11 at 02:50
  • For the sake of completeness, C# lets you use automatic storage for certain types (declared with `struct` instead of `class`), and the CLR itself allows the allocation of _most_ types on automatic storage too (through C++/CLI usually). – zneak Mar 16 '11 at 02:59
0

They do very different things. The first one allocates an object on the stack, the 2nd on the heap. The stack allocation only lasts for the lifetime of the declaring method; the heap allocation lasts until you delete the object.

The second way is the only way to dynamically allocate objects, but comes with the added complexity that you must remember to return that memory to the operating system (via delete/delete[]) when you are done with it.

Joe
  • 41,484
  • 20
  • 104
  • 125
0

The first way will create the object on the stack, and the object will go away when you return from the function it was created in.

The second way will create the object on the heap, and the object will stick around until you call delete foo;.

If the object is just a temporary variable, the first way is better. If it's more permanent data, the second way is better - just remember to call delete when you're finally done with it so you don't build up cruft on your heap.

Hope this helps!

Xavier Holt
  • 14,471
  • 4
  • 43
  • 56