简体   繁体   中英

Using placement new to call constructor within constructor

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?

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.

在C ++ 11中,您可以使用委托构造函数指定它:

Foo() : Foo(5) { }

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM