在没有new的情况下用c ++调用构造函数

Nil*_*ils 133 c++

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

Thing myThing("asdf");
Run Code Online (Sandbox Code Playgroud)

而不是这个:

Thing myThing = Thing("asdf");
Run Code Online (Sandbox Code Playgroud)

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

Jar*_*Par 141

这两条线实际上都是正确的,但却做了微妙的不同.

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

第二个有点复杂.它基本上做了以下

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

  • 我认为你的步骤不对.`Thing myThing = Thing(...)`不使用赋值运算符,它仍然是复制构造的,就像说'Thing myThing(Thing(...))`,并且不涉及默认构造的`Thing` (编辑:帖子后来得到纠正) (14认同)
  • 我想这些类型的操作都经过优化,因此在性能方面没有显着差异. (7认同)
  • 不,@ Jared,不能保证.但即使编译器选择执行该优化,复制构造函数仍然需要可访问(即,不受保护或私有),即使它未被实现或调用. (3认同)
  • 即使复制构造函数有副作用,也可以省略副本 - 请参阅我的答案:http://stackoverflow.com/questions/2722879/calling-constructors-in-c-without-new/2723266#2723266 (3认同)

kni*_*ttl 30

我假设第二行你的意思是:

Thing *thing = new Thing("uiae");
Run Code Online (Sandbox Code Playgroud)

这将是创建新动态对象(动态绑定和多态性所必需)并将其地址存储到指针的标准方法.您的代码执行JaredPar描述的内容,即创建两个对象(一个传递一个const char*,另一个传递一个const Thing&),然后~Thing()在第一个对象(const char*一个)上调用析构函数().

相比之下,这:

Thing thing("uiae");
Run Code Online (Sandbox Code Playgroud)

创建一个静态对象,该对象在退出当前范围时自动销毁.

  • OP的问题是正确的,这个答案完全涉及另一个问题(参见@JaredPar的回答) (3认同)
  • 不幸的是,这确实是创建新动态对象的最常见方法,而不是使用 auto_ptr、unique_ptr 或相关方法。 (2认同)

Dou*_*der 21

编译器可能会将第二种形式优化为第一种形式,但它不必.

#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;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


Ste*_*oss 10

很简单,两行都在堆栈上创建对象,而不是像'new'那样在堆上创建.第二行实际上涉及对复制构造函数的第二次调用,因此应该避免(它还需要按照注释中的说明进行更正).你应该尽可能地将堆栈用于小对象,因为它更快,但是如果你的对象要比堆栈框架存活更长时间,那么它显然是错误的选择.