在c ++中调用构造函数没有新的
我经常看到人们用C ++创build对象
Thing myThing("asdf");
而不是这个:
Thing myThing = Thing("asdf");
这似乎工作(使用gcc),至less只要没有涉及的模板。 我现在的问题是第一行是正确的,如果是的话,我应该使用它?
两条线实际上是正确的,但做了微妙的不同的事情。
第一行通过调用格式Thing(const char*)
的构造函数在堆栈上创build一个新对象。
第二个是更复杂一点。 它基本上做到以下几点
- 使用构造函数
Thing(const char*)
创buildThing
types的对象 - 使用构造函数
Thing(const Thing&)
创buildThing
types的对象 - 在步骤#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/编译这个源代码;
// 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一个函数指针或者什么东西?