Do the parentheses after the type name make a difference with new?
如果"测试"是一个普通类,那么以下两者之间是否存在任何差异:
和
1
| Test* test = new Test(); |
- 这与stackoverflow.com/questions/1613341/hellip相关(但不完全相同);
- 只需使用new test()确保它已初始化为零
让我们学点书生气吧,因为有一些差异实际上会影响代码的行为。以下大部分内容摘自对一篇"旧的新事物"文章的评论。
有时,新操作符返回的内存将被初始化,有时它将不取决于您正在更新的类型是POD(纯旧数据),或者它是一个包含POD成员的类,并且使用编译器生成的默认构造函数。
- 在C++ 1998中,初始化有2种类型:零和默认值。
- 在C++ 2003中进行了第三种初始化,增加了值初始化。
假设:
1 2 3
| 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编译器中,应该发生以下情况:
- new A不定值
new A()零初始化
new B—默认构造(b::m未初始化)
new B()—默认构造(b::m未初始化)
new C—默认构造(c::m初始化为零)
- new C()—默认构造(c::m初始化为零)
在C++ 03兼容编译器中,事情应该是这样工作的:
因此,在所有版本的C++中,EDCOX1与2的EDCOX1和EDCOX1之间的区别是3,因为A是POD。
在EDCOX1与5的情况下,C++ 98和C++ 03之间的行为有差异。
这是C++的一个尘土飞扬的角落,可能会让你发疯。当构造一个对象时,有时你想要/需要parens,有时你绝对不能拥有它们,有时它并不重要。
- 对于EDOCX1,3和EDCOX1,4,在C++ 03下,EDCOX1,5,5未初始化?那么对于struct D { D() : {} int m; }呢(即由于用户定义的ctor而不是pod,但没有提到m)?
- 似乎我的struct D在后面的旧的新事物评论线程中被提到了!对于new D和new D(),m没有初始化。
- @ J2Read OpHead,EDCOX1,11将默认在C++ 98中初始化对象,就像它与EDCOX1,12,EDCOX1,13,EDCOX1,4,EDCX1,3,但不使用EDCOX1,16。也就是说,缺省初始化总是在C++ 98中进行的:1)类是非POD和初始化器丢失,或者2)初始化器是EDCOX1 OR 2。如果对象是pod,则默认初始化为零,但调用非pod的默认构造函数。
- @利特布:谢谢,那么在C++ 03中EDCOX1的18个例子呢?迈克尔的回答只是说"调用默认的系数",但我不完全确定这意味着什么。
- 因此,new A意味着最好的性能,因为编译器很可能不会初始化它;虽然new A()比较安全,因为您不会遇到不确定的值,这是正确的吗?
- 有人能在C++ 11中添加什么吗?
- 似乎拥有一个需要new A()的struct A是不好的样式,因为您不能像在堆栈上那样创建它。最好用构造函数初始化。这是一个公平的评论吗?
- @乔恩:用C++ 11也可以在堆栈中实现这一点;EDCOX1(23)将使对象值初始化(相对于0),而不是EDCOX1(24),这将是默认初始化(垃圾)。
- @乔恩:添加了C++ 11的例子,现在它也关注堆栈上的默认初始化对象。
- 但是,就编码风格而言,写一个构造函数比依赖于类/结构的客户机知道它们需要对初始化进行值化更好,这公平吗?
- @乔恩:嗯,那要看情况而定。并非所有的类都是为外部消耗而编写的,客户机是一些不知道的Joe编码人员;有些类是为库的内部消耗而编写的,在这种情况下,我想使用pod更好,但在某些情况下,绝对有必要将var初始化为特定的状态(和perf)。这不是问题)那么,ctr似乎更好。
- = default语法适用于哪个规则?也就是说,如果您有,B() = default;,这是一个编译器生成的构造函数,那么我假设它在默认初始化时仍然会使B::m不初始化?
- 我删除了"C++ 11更新",因为它与问题的主题无关(EDOCX1,3,V.EDCOX1,4),所以非常混乱。在C++ 11中存在差异,其中值初始化的用户定义类型如果成员是内置类型,则初始化成员零,而在默认构造函数初始化列表中未初始化。
- @markingram afaik by do=default;您显式地提供了一个构造函数(即使它是由编译器生成的,所以在案例B中也是如此)。如果不提供构造函数,编译器可能以任何方式隐式生成它(您将保留在案例A中)。结果相同:新建A/B->默认初始化,新建A/B()->值初始化为零。但是,在C++ 11中,你不应该考虑POD,而是聚合…
- 要添加的另一个有趣的例子是struct D { D() { }; ~D(); int m; };,它有一个用户定义的构造函数,它没有显式初始化pod成员。
- new A - indeterminate value. new A() - zero-initialize。有人能解释一下吗?什么是不确定值,什么是零初始化?
- 你说"有时候你绝对不能拥有它们[括号]"。在什么情况下您不能添加它们?
- ^我也有同样的问题。我不认为包含括号有任何有害的语义。
- @kec:也许你想避免调用编译器生成的默认构造函数,因为这会调用所有成员的默认构造函数——这可能会产生你想要避免的副作用(例如,当你真正想要重用已经存在的东西时,打开文件描述符或套接字)。在我看来,如果你需要像那样破解你的代码,那么你的设计有一个缺陷,但是在现实世界中,你又会遇到一些你不能或不想经常改变的东西……
- @CupidVogel:不确定值意味着实际值取决于操作系统和新操作符的实现对您所获得的内存块所做的操作。零初始化意味着内存块全部为零。
- @kec搜索"最烦人的分析"。
- 在C++ 11/14中,IFF。a是一个类/结构/聚合,其默认ctor被显式/隐式定义为=default;且不会被隐式删除(=delete;),那么有一个区别:new A();确保所有未由默认ctor初始化的非引用数据成员(子对象)都是0-初始化的,而new A;不初始化。
- 因此,tl;dr是new A给成员一个不确定的值,new A()将成员值初始化为0…除非A定义了析构函数,在这种情况下,两个表达式都给成员提供不确定的值…除非A也定义了一个构造函数,在这种情况下,两个表达式都是零初始化成员…除非它是一个C++ 03编译器,在这种情况下,EDCOX1〔12〕将"值初始化"成员,而这在某种程度上是不同的(?)这么简单。
new Thing();明确表示需要调用构造函数,而new Thing;则表示不介意是否调用构造函数。
如果在具有用户定义构造函数的结构/类上使用,则没有区别。如果调用一个普通的结构/类(如struct Thing { int i; };),那么new Thing;就像malloc(sizeof(Thing));,而new Thing();像calloc(sizeof(Thing));,它得到零初始化。
Gotcha介于:
1 2 3 4 5
| struct Thingy {
~Thingy(); // No-longer a trivial class
virtual WaxOn();
int i;
}; |
EDCX1与24的EDCOX1,25的行为在这种情况下在C++ 98和C++ 2003之间发生了变化。查看迈克尔·伯尔的解释,了解如何以及为什么。
不,它们是一样的。但两者之间存在差异:
1
| Test t; // create a Test called t |
和
1
| Test t(); // declare a function called t which returns a Test |
这是因为基本的C++(和C)规则:如果某事物可能是一个声明,那么它就是一个声明。
编辑:重新初始化POD和非POD数据的问题,虽然我同意所说的一切,但我想指出的是,这些问题仅适用于新的或以其他方式构建的对象没有用户定义的构造函数的情况。如果有这样的构造器,将使用它。对于99.99%设计合理的类,会有这样一个构造函数,因此可以忽略这些问题。
- 请注意,这是一个特别重要的点,因为行"test t(5);"相当于"test t=test(5);"--但是"test t();"与"test t=test();"非常不同。+ 1
- -1、我不同意你关于这些问题可以忽略的说法。您不必精确地了解规则,但是您应该了解它们,以防必须在没有用户定义的默认构造函数的情况下新建一个类(然后您应该编写构造函数或查找规则)。
- -1对于已知的错误答案。您的编辑忽略了以前的C程序员编写的代码,这些程序员不理解/使用构造函数。
- 像struct point float v[3];这样的类呢?对于类似的事情,构造函数是一个坏主意,因为它会阻止所有漂亮的属性成为pod和aggregate。所以,在我看来,"问题可以忽略"是错误的。
- 我怀疑C++代码中有0.001%的地方使用C代码。
- 这个问题现在用C++ 11的统一初始化语法来解决。请参阅已接受的答案。
- 但它们不一样。这个答案显然是错误的。它应该被修正或删除,因为从高得票数来看,它似乎造成了一些混乱。
- "如果某个事物可能是一个声明,那么它就是一个声明。"这句话本身是正确的,但在这里没有帮助:一个对象定义(如Test t;)仍然是一个声明,所以两个候选者(obj def?FUNC DECL?)是声明,语句不能用于消除歧义。
- 实际上,语法只允许将Test t();解析为函数声明,因为()不能是初始值设定项,这需要一个非空的表达式列表。因此,没有模棱两可的开始。
一般来说,我们在第一种情况下有默认初始化,在第二种情况下有值初始化。
例如:如果是int(pod类型):
下一个行为取决于您的类型测试。我们有不同的例子:测试有默认的构造函数,测试生成了默认的构造函数,测试包含pod成员,非pod成员…
假设测试是一个具有已定义构造函数的类,则没有区别。后一种形式使测试的构造函数正在运行变得更加清晰,但这就是问题所在。