简体   繁体   English

使用placement new来在构造函数中调用构造函数

[英]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对象时:

Foo* f = new Foo();

I suppose variable _n is 5, however, it's NOT. 我想变量_n是5,但是,它不是。

It's ok in Java but NOT in c++. 它在Java中没问题,但在c ++中没有。

In addition, in Visual C++ 6 sp 6, 另外,在Visual C ++ 6 sp 6中,

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

works. 作品。

However, this expression is refused by gcc/g++ 4. 但是,这个表达式被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? 括号中的“this”有什么作用?

What the (this) does, is creates a brand new Foo object, at the place pointed at by this (this is called placement new). 什么(this)确实是创造了一个全新Foo对象,在地方指着用this (这就是所谓的安置新)。 You should only use it in arrays of char and unsigned char , nowhere else (and almost never there either). 你应该只在charunsigned char数组中使用它,在其他地方(并且几乎从不在那里)。 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. 既然你要构建Foo在其中的位置, this已经开工建设,你在做什么是不确定的行为,如果你有基类会泄漏资源得到处都是。 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. 在C ++ 11中,构造函数应该能够使用这种语法相互调用,但我不知道哪些编译器支持它。 According to Apache , it's supported by GCC 4.7 and Clang 3.0, but not yet Intel C++ nor VC++. 根据Apache的说法 ,它得到了GCC 4.7和Clang 3.0的支持,但还不支持英特尔C ++和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. 你用Foo() { Foo(5);}开始的代码开始构造this ,然后用参数5在堆栈上创建一个全新的Foo对象,然后销毁它,然后认为自己完全构造,而不初始化任何它是自己的价值观。 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)表示new运算符将使用this的地址作为初始化类的地址。

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 ; 我在这里遇到了同样的问题: 另一个C ++对象初始化审讯 ; feel free to look at the solution. 随便看看解决方案。

The correct syntax in C++ is C ++中的正确​​语法是

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 或者,C ++允许使用默认参数值,例如

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. 这种Java风格的编程是有效的C ++,但它有其优缺点以及至少一种其他替代方案。

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

is a "placement new" operator that calls a constructor on a pre-allocated memory. 是一个“placement new”运算符,它在预分配的内存上调用构造函数。

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. 现在,对于你的其他问题--C ++ 11允许完全相同(相互调用构造函数),但早期的标准(特别是MSVC 6使用的标准)没有那个,所以使用那些丑陋的init()方法是你的方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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