一个int()被称为什么?

15

一再强调原始类型没有构造函数。例如,当我调用Foo()时,_bar不会被初始化为0:

class Foo{
    int _bar;
};

显然 int() 不是一个构造函数。但它的名字是什么?

在这个例子中,我会说i是:(被构造?初始化?fooed?)

for(int i{}; i < 13; ++i)

Loki Astari提到了这里该技术有一定的名称。

根据Mike Seymour的回应,进行编辑:

#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


3
作为表达式,“int()”和“Foo()”在“函数表示法”中是“显式类型转换”,就像“int(5)”一样,但具有不同的规则。但我猜只有少数人使用这个名称来标识该特性。 - dyp
添加到dyp,我标记为重复的原因是(不知道它会立即关闭它!),T()创建一个值初始化的prvalue - David Rodríguez - dribeas
1
关于编译器的区别,VS是错误的。值初始化的规则要求Foo零初始化,这反过来意味着在Foo()_bar需要获得值0。 - David Rodríguez - dribeas
@DavidRodríguez-dribeas 是的,我的确在他的回答下的评论区与 Mike Seymour 进行了一番长时间的交流,从中我了解到了这一点。 - Jonathan Mee
2
@JonathanMee:众所周知,VS在不同形式的值初始化方面存在问题。我曾经有一组测试用例在那里失败了一段时间,在我们公司中,我们在一些情况下绕过编译器。 - David Rodríguez - dribeas
3
重新打开了这个问题,它不是真正的重复问题,因为这个问题的关键在于找出 T() 的意思是“值初始化”,而不是理解“值初始化”的含义(这是另一个问题的重点:https://dev59.com/aXI-5IYBdhLWcg3w6tFR)。 - David Rodríguez - dribeas
3个回答

9
它被反复强调过,基本类型没有构造函数。
是的。
例如,当我调用 Foo() 时,这个 bar 没有被初始化为 0。
是的。 Foo() 指定了值初始化,对于像这样没有自定义构造函数的类,这意味着在初始化其成员之前进行零初始化。因此,_bar 的值最终为零。(尽管在评论中提到,一个流行的编译器没有正确地对这种类进行值初始化。)
如果你使用默认初始化,它将不会被初始化。你无法对临时变量使用默认初始化;但声明的变量 Foo f; 或通过 new F 创建的对象将被默认初始化。原始类型的默认初始化不执行任何操作,使它们具有不确定���值。
如果该类有一个用户提供的默认构造函数,并且该构造函数没有明确初始化 _bar,那么它也将不会被初始化。同样,它将被默认初始化,没有效果。
所以很显然,int() 不是一个构造函数。但它的名字是什么?
作为一个表达式,它是一个类型为 int 的值初始化临时对象。
从语法上讲,它是“显式类型转换(函数符号)”的特例;但把这个术语用于除类型转换之外的任何事情都会相当令人困惑。
在这个例子中,我会说 i 是:(构造?初始化?fooed?)
被初始化。列表初始化(使用空列表),值初始化或零初始化,如果你想更具体一些。

3
整个类对象都被零初始化,这会将 _bar 初始化为零。 - Mike Seymour
2
@JonathanMee: 我不知道。也许你的编译器没有按照标准对对象进行值初始化。 - Mike Seymour
5
你的编译器有问题:https://connect.microsoft.com/VisualStudio/feedback/details/484295 - Mike Seymour
4
不,这是正确的做法。第一个是默认初始化,使其具有不确定的值;第二个是正确地零初始化。 - Mike Seymour
4
@JonathanMee 你可以在这里测试(http://rise4fun.com/vcpp)它已经在vc2015中成功修复。 - Predelnik
显示剩余14条评论

6
以下是int()的功能(需要注意,从语法上讲,int是一个简单类型说明符):

[C++11: 5.2.3/1]: 简单类型说明符(7.1.6.2)或typename说明符(14.6)后跟括号中的表达式列表会根据表达式列表构造指定类型的值。如果表达式列表是单个表达式,则类型转换表达式等效于相应的转换表达式(5.4)。如果指定的类型是类类型,则该类类型必须是完整的。如果表达式列表指定了多个值,则类型必须是具有适当声明的类(8.5、12.1),并且表达式T(x1, x2, ...)在效果上等同于声明T t(x1, x2, ...);对于一些虚构的临时变量t,其结果是t的prvalue值。

通俗地说,它表示使用空初始化程序构建临时int。但我认为你很难找到整个结构的正式名称。
这与int i{}不同,后者是一个完整的带初始值的命名对象的声明:你的i已经被声明、构造和初始化了。
(我不认为这与Loki在他评论中提到的内容有关。)

4
差不多了,除了更好的引用应该是下一个段落:“表达式T(),其中T是单一类型说明符...创建指定类型的值初始化的prvalue。” - David Rodríguez - dribeas

-1

如果你愿意,你可以称之为伪构造函数,这与析构函数的术语相呼应(C++11 §5.2.4讨论了伪析构函数调用)。无论如何,int()是类型int的默认值,即0。

关于“基本类型没有构造函数”的断言,这是一个非常愚蠢和不切实际的观点。从正式的角度来看,基本类型确实没有构造函数,但那些坚持这种说法的人并不太注重正式性。同样,从机器代码的角度来看,它们也没有构造函数,但对于那些认为这种说法很重要的人来说,机器代码就像魔法一样。然而,有一个区别,即从机器代码的角度来看,普通的非基本POD类型也可能缺少构造函数(从正式上讲,它们确实有构造函数),我怀疑那些提出这种说法的人甚至没有意识到这个问题,也就是说,我认为他们没有资格发表意见。对于任何绝对术语的声明都有类似的考虑:当你听到这样的声明时,几乎可以肯定,那些发表这种声明的人几乎不知道涉及什么问题,而这种声明只是不切实际和愚蠢的。

相反,当你在原始类型的上下文中听到“构造”或“构造函数调用”等术语时,请考虑它们可能具有的有意义的含义。形式只是定义的问题。重要的是,除了语言律师讨论外,在概念模型方面能够正常工作。


所有上述内容中,表达式T()在形式上不是“构造函数”,它在机器代码级别上也不是构造函数,在任何有意义的概念模型中也不是构造函数概念上的。它可以是一个构造函数调用(事实上,默认构造函数的定义是可以在源代码级别上不带参数调用),但请注意,没有构造函数调用的语法类别。
考虑到以上所有内容,我只会称其为构造函数调用,并且在需要更精确时,对于原始类型T,我会称其为伪构造函数调用

如果有人因此批评我,我会向他们发起决斗的挑战。


请注意,关于您的声明:

已经反复强调原始类型没有构造函数。例如,当我调用Foo()时,这个条形码没有初始化为0。

表达式Foo()执行值初始化,因此实例(在本例中)被清零。

关于未初始化的本地自动变量的普通类型缺乏初始化的情况,对于任何没有用户定义构造函数的类型都是相同的,即使有一个使用的定义构造函数,如果该构造函数不初始化事物。

这有时会让C++初学者感到震惊。


3
@匿名的点踩者:请公开陈述您的异议,这样我才能向您展示您思考中的错误。不确定能否拯救您,但我会尝试。 :) - Cheers and hth. - Alf
@Cheersanhth.-Alf,我不确定我是否理解了你最后的编辑:“您在没有用户定义构造函数的任何类型中都有相同的情况”,您能详细说明一下吗? - Jonathan Mee
@JonathanMee:我是指当一个本地变量没有被初始化的情况。抱歉,我已经澄清了这一点(原帖中错误的断言给这个问题带来了混乱,我没有注意到他的Foo是类型)。 - Cheers and hth. - Alf
在阅读你和Mike Seymour的评论之前,我真的不理解“值初始化”在默认构造函数方面意味着什么。<-报名参加C++初学者列表 :/ - Jonathan Mee
1
@匿名的踩贴者:这就像是三个没有解释的踩贴。我们应该进行一场决斗。请直播,我会观看。 - Jonathan Mee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接