4

was struggling these days.

The problem is the constructor calling.

I wrote a piece of code like:

#include <iostream>
using namespace std;

class Foo
{

  private: int _n;

  public:

  Foo() { Foo(5);}

  Foo(int n) {_n=n; cout << n << endl; }

};

int main()
{
   Foo* foo = new Foo();
   return 0;

}

When I constructed a Foo object outside using the default constructor:

Foo* f = new Foo();

I suppose variable _n is 5, however, it's NOT.

It's ok in Java but NOT in c++.

In addition, in Visual C++ 6 sp 6,

Foo() {this->Foo(5);}

works.

However, this expression is refused by gcc/g++ 4.

Finally, I found out the solution.

Simply changing the default constructor into

Foo() {Foo(5);}

into

Foo() { new (this) Foo(5); }

solves the problem.

What does "this" in parentheses do?

bsb3166
  • 41
  • 2
  • 1
    This is covered by Googl... err.. the [C++ FAQ](http://www.parashift.com/c++-faq/index.html): ["Can one constructor of a class call another constructor of the same class to initialize the this object?"](http://www.parashift.com/c++-faq/init-methods.html) – Sean Bright Jul 18 '12 at 18:45
  • 2
    "It's ok in Java but NOT in c++." Don't even bother trying to make sense of C++ based on what you know from Java. Not only it doesn't help, it is actually harmful. – R. Martinho Fernandes Jul 18 '12 at 18:46
  • 4
    If I'm not mistaken, one way around this would be to not declare `Foo()` and instead change the declaration for `Foo(int n)` to `Foo(int n=5)`. This way, that constructor can be used as the default. It's been a while since I did any C++ programming, so I could be wrong on that – Dan F Jul 18 '12 at 18:47
  • http://stackoverflow.com/questions/7349183/constructor-chaining-in-c –  Jul 18 '12 at 18:50
  • 2
    Just to clarify (not answering your question): in your first example, the buggy code `Foo() { Foo(5);}` constructs an object of type Foo with parameter 5, does nothing with it and immediately destroys it – anatolyg Jul 18 '12 at 18:53

5 Answers5

4

What the (this) does, is creates a brand new Foo object, at the place pointed at by this (this is called placement new). You should only use it in arrays of char and unsigned char, nowhere else (and almost never there either). Since you are constructing a Foo at the location where this has already started construction, what you are doing is undefined behavior, and would leak resources all over the place if you had base classes. Historically, the normal thing to do is merely move the initialization to a private function.

class Foo {
public:    
  Foo() { init(5);}    
  Foo(int n) {init(n);}
private: 
  int _n;
  void init(int n) {
    _n=n;
  };
}

In C++11 constructors should be able to call each other with this syntax, but I don't know which compilers support it yet. According to Apache, it's supported by GCC 4.7 and Clang 3.0, but not yet Intel C++ nor VC++.

class Foo {
public:    
  Foo() : Foo(5) {}
  Foo(int n) {_n=n;}
private: 
  int _n;
}

The code you started with Foo() { Foo(5);} begins construction of this, then creates a brand new Foo object on the stack with the parameter 5, then destroys it, and then considers itself completely constructed, without initializing any of it's own values. That is why it compiled and ran, but didn't appear to do anything.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • Everybody missed the fact that his code has a bug. He is calling the constructor for Foo(5), but the temporary object is destroyed at the end of the block. –  Jul 18 '12 at 18:58
  • @user195488: No, the temporary object is destroyed at the semicolon. – jdh8 Aug 04 '14 at 07:15
3

In C++11 you specify this with a delegating constructor:

Foo() : Foo(5) { }
Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
1

The (this) in parenthesis means that the new operator will use the address of this as the address to initalize the class.

This is very dangerous: you're in the constructor of the current object, and you invoke a new constructor on the same memory space. Just imagine what would happen if you inherit from another class!

As for your problem, you can't call another overloaded constructor from within the constructor. The typical solution is to have a method to initialize your class:

class Foo
{
  int _n;
public:
  Foo() { init(5); }
  Foo( int i) { init(i); }
  void init(int i) { _n = i; }
};

I had quite the same problem here: Yet another C++ Object initialization interrogation ; feel free to look at the solution.

Community
  • 1
  • 1
Gui13
  • 12,993
  • 17
  • 57
  • 104
0

The correct syntax in C++ is

class Foo { 

  private: int _n; 

  public: 

  Foo() : Foo(5) {} 

  Foo(int n) _n(n) {} // As suggested by another member's edit, initializer lists are preferred

};

Alternatively, C++ allows default parameter values, such as

Foo(int n = 5);

This allows you to write one constructor rather than two.

Also, you should be sure to learn about the difference between inline and non-inline functions. This Java-style of programming is valid C++, but it has it's pros and cons along with at least one other alternative.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • 2
    Note that this is only valid in C++11. – Xeo Jul 18 '12 at 18:47
  • @Xeo It's been a while since I've programmed seriously with C++. I am pretty sure I was able to call other constructors from the initializer list prior to C++11. Perhaps my memory is faulty, though. \*shrugs\* – Code-Apprentice Jul 18 '12 at 18:50
0
Foo() { new (this) Foo(5); }

is a "placement new" operator that calls a constructor on a pre-allocated memory.

Now, for you other question - C++11 allows exactly that (calling constructors from one another) but the earlier standard (especially the one used by MSVC 6) doesn't have that so the use of those ugly init() methods is the way to go for you.

YePhIcK
  • 5,816
  • 2
  • 27
  • 52