如果'Test'是一个普通类,那么以下两者之间是否有区别:

Test* test = new Test;

and

Test* test = new Test();

当前回答

新事物();是显式的,你想要一个构造函数调用while new Thing;表示您不介意不调用构造函数。

如果在带有用户定义构造函数的结构/类上使用,则没有区别。如果在一个普通的struct/类上调用(例如struct Thing {int i;};)然后new Thing;是像malloc(大小(东西));而new Thing();是像calloc(sizeof(Thing));-它得到零初始化。

问题就在这两者之间:

struct Thingy {
  ~Thingy(); // No-longer a trivial class
  virtual WaxOn();
  int i;
};

新事物的行为;vs new Thingy();在这种情况下,在c++ 98和c++ 2003之间变化。详见Michael Burr的解释。

其他回答

new的规则类似于初始化具有自动存储持续时间的对象时所发生的情况(尽管由于令人烦恼的解析,语法可能略有不同)。

如果我说:

int my_int; // default-initialize → indeterminate (non-class type)

那么my_int有一个不确定的值,因为它是非类类型。或者,我可以像这样对my_int进行值初始化(对于非类类型,是零初始化):

int my_int{}; // value-initialize → zero-initialize (non-class type)

(当然,我不能使用(),因为这将是一个函数声明,但int()的工作原理与int{}相同,可以构造一个临时。)

然而,对于类类型:

Thing my_thing; // default-initialize → default ctor (class type)
Thing my_thing{}; // value-initialize → default-initialize → default ctor (class type)

调用默认构造函数来创建Thing,没有异常。

所以,规则或多或少是:

Is it a class type? YES: The default constructor is called, regardless of whether it is value-initialized (with {}) or default-initialized (without {}). (There is some additional prior zeroing behavior with value-initialization, but the default constructor is always given the final say.) NO: Were {} used? YES: The object is value-initialized, which, for non-class types, more or less just zero-initializes. NO: The object is default-initialized, which, for non-class types, leaves it with an indeterminate value (it effectively isn't initialized).

这些规则精确地转换为新语法,添加的规则()可以代替{},因为new永远不会被解析为函数声明。所以:

int* my_new_int = new int; // default-initialize → indeterminate (non-class type)
Thing* my_new_thing = new Thing; // default-initialize → default ctor (class type)
int* my_new_zeroed_int = new int(); // value-initialize → zero-initialize (non-class type)
     my_new_zeroed_int = new int{}; // ditto
       my_new_thing = new Thing(); // value-initialize → default-initialize → default ctor (class type)

(这个答案包含了c++ 11中概念上的变化,上面的答案目前没有;值得注意的是,一个新的标量或POD实例将以一个不确定的值结束,现在技术上是默认初始化的(对于POD类型,技术上调用一个普通的默认构造函数)。虽然这并没有引起行为上的实际变化,但它确实在一定程度上简化了规则。)

我在下面写了一些示例代码,作为Michael Burr回答的补充:

#include <iostream>

struct A1 {
    int i;
    int j;
};

struct B {
    int k;
    B() : k(4) {}
    B(int k_) : k(k_) {}
};

struct A2 {
    int i;
    int j;
    B b;
};

struct A3 {
    int i;
    int j;
    B b;
    A3() : i(1), j(2), b(5) {}
    A3(int i_, int j_, B b_): i(i_), j(j_), b(b_) {}
};

int main() {
    {
        std::cout << "Case#1: POD without ()\n";
        A1 a1 = {1, 2};
        std::cout << a1.i << " " << a1.j << std::endl;
        A1* a = new (&a1) A1;
        std::cout << a->i << " " << a->j  << std::endl;
    }
    {
        std::cout << "Case#2: POD with ()\n";
        A1 a1 = {1, 2};
        std::cout << a1.i << " " << a1.j << std::endl;
        A1* a = new (&a1) A1();
        std::cout << a->i << " " << a->j  << std::endl;
    }
    {
        std::cout << "Case#3: non-POD without ()\n";
        A2 a1 = {1, 2, {3}};
        std::cout << a1.i << " " << a1.j << " " << a1.b.k << std::endl;
        A2* a = new (&a1) A2;
        std::cout << a->i << " " << a->j << " " << a->b.k << std::endl;
    }
    {
        std::cout << "Case#4: non-POD with ()\n";
        A2 a1 = {1, 2, {3}};
        std::cout << a1.i << " " << a1.j << " " << a1.b.k  << std::endl;
        A2* a = new (&a1) A2();
        std::cout << a->i << " " << a->j << " " << a1.b.k << std::endl;
    }
    {
        std::cout << "Case#5: user-defined-ctor class without ()\n";
        A3 a1 = {11, 22, {33}};
        std::cout << a1.i << " " << a1.j << " " << a1.b.k << std::endl;
        A3* a = new (&a1) A3;
        std::cout << a->i << " " << a->j << " " << a->b.k << std::endl;
    }
    {
        std::cout << "Case#6: user-defined-ctor class with ()\n";
        A3 a1 = {11, 22, {33}};
        std::cout << a1.i << " " << a1.j << " " << a1.b.k  << std::endl;
        A3* a = new (&a1) A3();
        std::cout << a->i << " " << a->j << " " << a1.b.k << std::endl;
    }
    return 0;
}

/*
output with GCC11.1(C++20)
Case#1: POD without ()
1 2
1 2
Case#2: POD with ()
1 2
0 0
Case#3: non-POD without ()
1 2 3
1 2 4
Case#4: non-POD with ()
1 2 3
0 0 4
Case#5: user-defined-ctor class without ()
11 22 33
1 2 5
Case#6: user-defined-ctor class with ()
11 22 33
1 2 5
*/

一般来说,第一种情况是默认初始化,第二种情况是值初始化。

例如: 如果是int (POD类型):

Int *test = new Int -我们有任意的初始化,*test的值可以是任意的。 Int *test = new Int () - *test的值为0。

接下来的行为取决于你的测试类型。 我们有不同的情况:测试有默认构造函数,测试生成默认构造函数,测试包含POD成员,非POD成员…

新事物();是显式的,你想要一个构造函数调用while new Thing;表示您不介意不调用构造函数。

如果在带有用户定义构造函数的结构/类上使用,则没有区别。如果在一个普通的struct/类上调用(例如struct Thing {int i;};)然后new Thing;是像malloc(大小(东西));而new Thing();是像calloc(sizeof(Thing));-它得到零初始化。

问题就在这两者之间:

struct Thingy {
  ~Thingy(); // No-longer a trivial class
  virtual WaxOn();
  int i;
};

新事物的行为;vs new Thingy();在这种情况下,在c++ 98和c++ 2003之间变化。详见Michael Burr的解释。

让我们来研究一下,因为有些差异实际上会影响代码的行为。以下大部分内容摘自对一篇“新旧事物”文章的评论。

有时new操作符返回的内存将被初始化,有时则不会,这取决于您要更新的类型是POD(普通旧数据),还是包含POD成员并使用编译器生成的默认构造函数的类。

在c++ 1998中,有两种初始化类型:0和default 在c++ 2003中增加了第三种初始化类型,值初始化。

假设:

struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

在c++ 98编译器中,应该发生以下情况:

新A -不定值 new A() -零初始化 new B -默认构造(B::m未初始化) new B() -默认构造(B::m未初始化) 新建C -默认构造(C::m为零初始化) new C() -默认构造(C::m是零初始化的)

在c++ 03兼容的编译器中,事情应该这样工作:

新A -不定值 new A() - value-initialize A,这是零初始化,因为它是一个POD。 new B -默认初始化(保留B::m未初始化) new B() - value- initialization B,它对所有字段进行零初始化,因为它的默认ctor是编译器生成的,而不是用户定义的。 new C - default-初始化C,它调用默认的ctor函数。 new C() -值初始化C,它调用默认的ctor。

所以在c++的所有版本中,新a和新a()之间是有区别的,因为a是POD。

对于new B()的情况,c++ 98和c++ 03之间的行为有所不同。

这是c++的一个让你抓狂的角落。在构造一个对象时,有时你想要/需要paren,有时你绝对不能拥有它们,有时这无关紧要。