134

What's the difference between lines 1 , 2 , 3 , 4?

When do I use each?

Why line 3 prints the constructor Foo and line 7 returns an error and line 8 doesn't?

#include <iostream>     
using namespace std;

class Foo
 {
   public:
   Foo ( )
   {
      cout << "constructor Foo\n";
   }               
};

class Bar
 {
   public:
   Bar ( Foo )
   {
      cout << "constructor Bar\n";
   }
};

int main()
{
   /* 1 */ Foo* foo1 = new Foo ();
   /* 2 */ Foo* foo2 = new Foo;
   /* 3 */ Foo foo3;
   /* 4 */ Foo foo4 = Foo::Foo();

   /* 5 */ Bar* bar1 = new Bar ( *new Foo() );
   /* 6 */ Bar* bar2 = new Bar ( *new Foo );
   /* 7 */ Bar* bar3 = new Bar ( Foo foo5 );
   /* 8 */ Bar* bar3 = new Bar ( Foo::Foo() );

   return 1;
}
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
Kolyunya
  • 5,973
  • 7
  • 46
  • 81

3 Answers3

160
   /* 1 */ Foo* foo1 = new Foo ();

Creates an object of type Foo in dynamic memory. foo1 points to it. Normally, you wouldn't use raw pointers in C++, but rather a smart pointer. If Foo was a POD-type, this would perform value-initialization (it doesn't apply here).

   /* 2 */ Foo* foo2 = new Foo;

Identical to before, because Foo is not a POD type.

   /* 3 */ Foo foo3;

Creates a Foo object called foo3 in automatic storage.

   /* 4 */ Foo foo4 = Foo::Foo();

Uses copy-initialization to create a Foo object called foo4 in automatic storage.

   /* 5 */ Bar* bar1 = new Bar ( *new Foo() );

Uses Bar's conversion constructor to create an object of type Bar in dynamic storage. bar1 is a pointer to it.

   /* 6 */ Bar* bar2 = new Bar ( *new Foo );

Same as before.

   /* 7 */ Bar* bar3 = new Bar ( Foo foo5 );

This is just invalid syntax. You can't declare a variable there.

   /* 8 */ Bar* bar3 = new Bar ( Foo::Foo() );

Would work and work by the same principle to 5 and 6 if bar3 wasn't declared on in 7.

5 & 6 contain memory leaks.

Syntax like new Bar ( Foo::Foo() ); is not usual. It's usually new Bar ( (Foo()) ); - extra parenthesis account for most-vexing parse. (corrected)

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 2
    Actually, is `Foo::Foo()` even legal? I thought it wasn’t. – Konrad Rudolph Sep 03 '12 at 13:30
  • Syntax like new Bar `( Foo::Foo() );` is not usual. It's usually `new Bar ( (Foo()) );` But what is TWO classes in this scope has a `Foo` method? – Kolyunya Sep 03 '12 at 13:30
  • 1
    The most vexing parse can't happen in a `new` expression though ;) – R. Martinho Fernandes Sep 03 '12 at 13:30
  • @KonradRudolph: Yes, it is legal. The language determines that the name of the type is injected into the definition of the type, so any number of nested `Foo::Foo::..::Foo()` will resolve to exactly the same thing: `Foo()`. This is one of those cases where simplifying the language leaves to allowing mysterious code. – David Rodríguez - dribeas Sep 03 '12 at 13:33
  • @Kolyunya: I don't understand you concern, can you explain: *what is TWO classes in this scope has a `Foo` method?* `Foo::Foo` is a convoluted way of typing `Foo()` which is the name of a type and a set of parenthesis. There can only be *one* type returned by lookup with a particular name --although if there was a function found by lookup named `Foo` before the class is encountered, that would be called, but this is orthogonal to the problem at hand. – David Rodríguez - dribeas Sep 03 '12 at 13:37
  • @LuchianGrigore thanks for a great reply. I thought, `Foo()` is a name of method, but now I see, it's a name of type. Ok. Can I ask you the last question: why I MUST delete instances created with `new` and I mustn't delete those, created like `Foo foo1`? – Kolyunya Sep 03 '12 at 13:42
  • @Kolyunya because by using `new`, you explictly tell the compiler you **want** to manage the resource yourself. Sometimes, you want the resource to live longer than the scope it's declared in. Google for dynamic allocation. – Luchian Grigore Sep 03 '12 at 13:43
  • @LuchianGrigore thanks much! I'm gonna read about it and get a new book... Btw, do I get it correctly, that those objects, created like `Foo foo` will be deleted automatically when the object in which they are created is deleted? Right? – Kolyunya Sep 03 '12 at 13:45
  • @Kolyunya yes, if they are part of an object. Everything you don't create with `new` is deleted automatically. – Luchian Grigore Sep 03 '12 at 13:46
  • @DavidRodríguez-dribeas "The language determines that the name of the type is injected into the definition of the type", could ypu please elaborate on what that means? Thanks – AturSams Jan 04 '14 at 20:00
  • @ArthurWulfWhite: Inside the class definition, the name of the class itself is added for lookup purposes, as if it was a member, somehow equivalent to `struct Type { typedef ::Type Type; };` (although this is illegal code). This means that `Type::Type` is equivalent to `Type`, and so `Type::Type::Type` is also equivalent to `Type` for the purpose of lookup. The expression `Foo::Foo()` is equivalent to `Foo`; it is not the name of the constructor inside the class, but rather the type `Foo()` which creates an value-initialized temporary of type `Foo`. Not sure if this is any clearer. – David Rodríguez - dribeas Jan 04 '14 at 22:07
26
  1. Allocates some dynamic memory from the free store, and creates an object in that memory using its default constructor. You never delete it, so the memory is leaked.
  2. Does exactly the same as 1; in the case of user-defined types, the parentheses are optional.
  3. Allocates some automatic memory, and creates an object in that memory using its default constructor. The memory is released automatically when the object goes out of scope.
  4. Similar to 3. Notionally, the named object foo4 is initialised by default-constructing, copying and destroying a temporary object; usually, this is elided giving the same result as 3.
  5. Allocates a dynamic object, then initialises a second by copying the first. Both objects are leaked; and there's no way to delete the first since you don't keep a pointer to it.
  6. Does exactly the same as 5.
  7. Does not compile. Foo foo5 is a declaration, not an expression; function (and constructor) arguments must be expressions.
  8. Creates a temporary object, and initialises a dynamic object by copying it. Only the dynamic object is leaked; the temporary is destroyed automatically at the end of the full expression. Note that you can create the temporary with just Foo() rather than the equivalent Foo::Foo() (or indeed Foo::Foo::Foo::Foo::Foo())

When do I use each?

  1. Don't, unless you like unnecessary decorations on your code.
  2. When you want to create an object that outlives the current scope. Remember to delete it when you've finished with it, and learn how to use smart pointers to control the lifetime more conveniently.
  3. When you want an object that only exists in the current scope.
  4. Don't, unless you think 3 looks boring and what to add some unnecessary decoration.
  5. Don't, because it leaks memory with no chance of recovery.
  6. Don't, because it leaks memory with no chance of recovery.
  7. Don't, because it won't compile
  8. When you want to create a dynamic Bar from a temporary Foo.
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • `1. Allocates some dynamic memory from the free store, and creates an object in that memory using its default constructor. You never delete it, so the memory is leaked.` Why I never delete it? I can just call `delete foo1` – Kolyunya Sep 03 '12 at 16:44
  • 2
    @Kolyunya: Yes you can, and should. But you don't do that in your example code, and I though it worth pointing that out. – Mike Seymour Sep 03 '12 at 16:48
5

Lines 1,2,3,4 will call the default constructor. They are different in the essence as 1,2 are dynamically created object and 3,4 are statically created objects.

In Line 7, you create an object inside the argument call. So its an error.

And Lines 5 and 6 are invitation for memory leak.

Coding Mash
  • 3,338
  • 5
  • 24
  • 45