在c ++中调用构造函数没有新的

我经常看到人们用C ++创build对象

Thing myThing("asdf"); 

而不是这个:

 Thing myThing = Thing("asdf"); 

这似乎工作(使用gcc),至less只要没有涉及的模板。 我现在的问题是第一行是正确的,如果是的话,我应该使用它?

两条线实际上是正确的,但做了微妙的不同的事情。

第一行通过调用格式Thing(const char*)的构造函数在堆栈上创build一个新对象。

第二个是更复杂一点。 它基本上做到以下几点

  1. 使用构造函数Thing(const char*)创buildThingtypes的对象
  2. 使用构造函数Thing(const Thing&)创buildThingtypes的对象
  3. 在步骤#1中创build的对象上调用~Thing()

我认为你的第二行你的意思是:

 Thing *thing = new Thing("uiae"); 

这将是创build新的dynamic对象(dynamic绑定和多态性所必需的)并将它们的地址存储到指针的标准方式。 你的代码完成JaredPar描述的任务,即创build两个对象(一个传递一个const char* ,另一个传递一个const Thing& ),然后调用第一个对象( const char* one)的析构函数( ~Thing() )。

相比之下,这个:

 Thing thing("uiae"); 

创build一个静态对象,在退出当前作用域时会自动销毁。

编译器可能会将第二种forms优化成第一种forms,但并不一定。

 #include <iostream> class A { public: A() { std::cerr << "Empty constructor" << std::endl; } A(const A&) { std::cerr << "Copy constructor" << std::endl; } A(const char* str) { std::cerr << "char constructor: " << str << std::endl; } ~A() { std::cerr << "destructor" << std::endl; } }; void direct() { std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl; A a(__FUNCTION__); static_cast<void>(a); // avoid warnings about unused variables } void assignment() { std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl; A a = A(__FUNCTION__); static_cast<void>(a); // avoid warnings about unused variables } void prove_copy_constructor_is_called() { std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl; A a(__FUNCTION__); A b = a; static_cast<void>(b); // avoid warnings about unused variables } int main() { direct(); assignment(); prove_copy_constructor_is_called(); return 0; } 

来自gcc 4.4的输出:

 TEST: direct char constructor: direct destructor TEST: assignment char constructor: assignment destructor TEST: prove_copy_constructor_is_called char constructor: prove_copy_constructor_is_called Copy constructor destructor destructor 

很简单,两行都在栈上创build对象,而不是像“新build”那样在堆上创build对象。 第二行实际上涉及到复制构造函数的第二次调用,因此应该避免(也需要按照注释中的指示更正)。 你应该尽可能的使用小物件堆栈,因为它比较快,但是如果你的物件要比堆栈架存活更长的时间,那显然是错误的select。

理想情况下,编译器会优化第二个,但这不是必需的。 第一个是最好的方法。 但是,理解C ++中栈和堆的区别是非常重要的,因为你必须pipe理自己的堆内存。

附加到JaredPar答案

1 – 通常的ctor,与临时对象的第二function类似。

在这里用不同的编译器在http://melpon.org/wandbox/编译这个源代&#x7801;

 // turn off rvo for clang, gcc with '-fno-elide-constructors' #include <stdio.h> class Thing { public: Thing(const char*){puts(__FUNCTION__ );} Thing(const Thing&){puts(__FUNCTION__ );} ~Thing(){puts(__FUNCTION__);} }; int main(int /*argc*/, const char** /*argv*/) { Thing myThing = Thing("asdf"); } 

你会看到结果。

来自ISO / IEC 14882 2003-10-15

8.5,第12部分

你的第一和第二build设被称为直接初始化

12.1,第13部分

可以使用function符号types转换(5.2.3)来创build其types的新对象。 [注意:语法看起来像构造函数的显式调用。 ] …以这种方式创build的对象是未命名的。 [注:12.2描述了临时对象的生命周期。 ] [注:显式构造函数调用不产生左值,参见3.10。 ]


在哪里阅读关于RVO:

12特殊成员函数/ 12.8复制类对象/第15部分

当符合某些标准时, 即使对象的复制构造函数和/或析构函数具有副作用 ,实现也可以省略类对象的复制构造。

用注释中的编译器标志closures它来查看这样的复制行为)

我玩了一下,当一个构造函数不带任何参数时,语法似乎变得很奇怪。 让我举个例子:

 #include <iostream> using namespace std; class Thing { public: Thing(); }; Thing::Thing() { cout << "Hi" << endl; } int main() { //Thing myThing(); // Does not work Thing myThing; // Works } 

所以只需要写myThing w / o括号实际上是调用构造函数,而Thing myThing()使得编译器要创build一个函数指针或者什么东西?