被一遍又一遍地重复,基元类型没有构造函数。例如,当我调用Foo()
时,此_bar
未初始化为0:
class Foo{
int _bar;
};
所以显然int()
不是构造函数。但它叫什么名字?
在这个例子中,我会说i
是:(构造的?初始化的?fooed的?(
for(int i{}; i < 13; ++i)
洛基·阿斯塔里(Loki Astari(在这里提到,这项技术有某种名称。
编辑以回应迈克·西摩:
#include <iostream>
using namespace std;
class Foo{
int _bar;
public:
void printBar(){ cout << _bar << endl; }
};
int main()
{
Foo foo;
foo.printBar();
Foo().printBar();
return 0;
}
在 Visual Studio 2013 上运行此代码会产生:
3382592 3382592
有趣的是,在 gcc 4.8.1 产量上:
134514651 0
一遍又一遍地重复说基元类型没有构造函数。
没错。
例如,当我调用
Foo()
时,此栏未初始化为 0
是的,它是。 Foo()
指定值初始化,对于像这样没有用户提供的构造函数的类,这意味着它在初始化其成员之前初始化为零。所以_bar
最终得到值零。(尽管,如注释中所述,一个流行的编译器没有正确地对此类进行值初始化。
如果要改用默认初始化,则不会对其进行初始化。你不能用临时的来做到这一点;但是声明的变量Foo f;
或对象 new F
将被默认初始化。基元类型的默认初始化不执行任何操作,使它们具有不确定的值。
如果类具有用户提供的默认构造函数,并且该构造函数没有专门初始化_bar
,则也不会初始化它。同样,它将默认初始化,不起作用。
所以很明显 int(( 不是构造函数。但它叫什么名字?
作为一个表达式,它是类型 int
的值初始化临时。
从语法上讲,它是"显式类型转换(函数表示法("的特例;但是将该术语用于类型转换以外的任何内容会相当令人困惑。
在这个例子中,我会说
i
是:(构造的?初始化的?fooed的?(
已初始化。列表初始化(使用空列表(、值初始化或零初始化(如果要更具体(。
以下是int()
的作用(请记住,从语法上讲,int
是一个简单的类型说明符(:
通
[C++11: 5.2.3/1]:
简单类型说明符 (7.1.6.2( 或类型名说明符 (14.6( 后跟带括号的表达式列表在给定表达式列表的情况下构造指定类型的值。如果表达式列表是单个表达式,则类型转换表达式等效(在定义性上,如果在含义上定义(与相应的强制转换表达式 (5.4( 等效。如果指定的类型是类类型,则该类类型应完整。如果表达式列表指定了多个值,则该类型应为具有适当声明的构造函数 (8.5, 12.1( 的类,并且表达式T(x1, x2, ...)
在效果上等效于声明T t(x1, x2, ...)
;对于一些发明的临时变量t
,结果是t
的值作为 prvalue 。
俗地说,它表示具有空初始化器的临时int
的构造。不过,我认为您很难为整个构造找到一个正式的名称。
这与 int i{}
不同,后者是带有初始化器的命名对象的完整声明:您的i
已被声明、构造和初始化。
(我不认为这些都与洛基在评论中所说的有关。
,可以将其称为伪构造函数,镜像析构函数的术语(伪析构函数调用在C++11 §5.2.4中讨论(。无论如何,int()
是类型 int
的默认值,即 0。
关于"基元类型没有构造函数"的断言,这是一个相当愚蠢和不切实际的观点。从形式的角度来看,基元类型没有构造函数,但那些坚持这种断言的人根本不那么喜欢正式的。此外,从机器代码的角度来看,他们没有,但同样,对于那些认为断言很重要的人来说,机器代码就像魔术一样。但是,有一个区别,即从机器代码的角度来看,常见的非原始POD类型也可能缺少构造函数(它们确实在形式上具有构造函数(,并且我再次怀疑提出该断言的人是否意识到了这些问题,即我认为他们没有资格发表意见。对于任何绝对的术语主张,你几乎可以肯定,当你听到这样的主张时,那些提出这种说法的人几乎不知道所涉及的内容,而且这种说法是不切实际和愚蠢的。
相反,当你在基元类型的上下文中听到例如"构造"或"构造函数调用"时,想想它的意义。正式只是一个定义问题。除了语言律师讨论之外,重要的是有一个可行的概念模型。
综上所述,表达式T()
在形式上不是"构造函数",在机器代码级别上不是构造函数,在任何有意义的概念模型中,在概念上也不是构造函数。
(实际上默认构造函数的定义是,它可以在源代码级别调用,没有参数(,但请注意,构造函数调用没有语法类别。
考虑到上述所有内容,我将其称为构造函数调用,当需要更精确时,对于原始类型T
,我会将其称为伪构造函数调用。
如果有人因此批评我,我会挑战他们进行决斗。
请注意,关于您的陈述
">一遍又一遍地重复说基元类型没有构造函数。例如,当我调用
Foo()
时,此栏未初始化为 0
表达式Foo()
执行值初始化,以便实例(在本例中(为零。
关于通常缺乏没有初始值设定项的基元类型的局部自动变量的初始化,对于没有用户定义的构造函数的任何类型,即使有一个使用的已定义构造函数,如果该构造函数不初始化事物,您也有相同的情况。
这有时会让C++初学者感到震惊。