【问题标题】:What is an int() Called?什么是 int() 调用?
【发布时间】:2015-02-11 03:47:01
【问题描述】:

原始类型没有构造函数已经被反复强调了。例如,当我调用Foo() 时,此_bar 未初始化为0:

class Foo{
    int _bar;
};

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

在本例中,我会说i 是:(已构造?已初始化?已装错?)

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

Loki Astari 提到 here 该技术有某种名称。

编辑回复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

【问题讨论】:

  • 作为表达式,int()Foo() 在语法上是“功能表示法”中的“显式类型转换”,就像int(5),但规则不同。但我猜只有少数人使用该名称来识别该功能。
  • 添加到 dyp,以及我标记为重复的原因(不知道它会立即关闭!),T() 创建了一个值初始化的 prvalue
  • 关于编译器的区别,VS是错误的。 值初始化的规则要求Foo零初始化,这反过来意味着_bar需要在Foo()中获取值0
  • @JonathanMee:已知 VS 在不同形式的 值初始化 方面存在问题。我有一组测试用例在那里失败了一段时间,在我的公司中,我们在少数情况下围绕编译器工作。
  • 重新打开了这个问题,并不是真正的重复,因为这个问题的问题是发现 T() 意味着 value-initialization,而不是理解什么 value-初始化 意味着(这是另一个问题的重点:stackoverflow.com/questions/1613341/…

标签: c++ initialization primitive nomenclature construction


【解决方案1】:

原始类型没有构造函数已经被反复强调了。

没错。

例如,当我调用 Foo() 时,此栏未初始化为 0

是的。 Foo() 指定值初始化,对于像这样没有用户提供的构造函数的类,这意味着它在初始化其成员之前是零初始化的。所以_bar 的值为零。 (尽管如 cmets 中所述,一种流行的编译器无法正确地对此类类进行值初始化。)

如果你改用默认初始化,它不会被初始化。你不能用临时的来做到这一点;但是声明的变量Foo f;new F 的对象将被默认初始化。原始类型的默认初始化什么都不做,给它们留下一个不确定的值。

如果该类有一个用户提供的默认构造函数,并且该构造函数没有专门初始化_bar,它也不会被初始化。同样,它将被默认初始化,没有任何效果。

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

作为一个表达式,它是 int 类型的值初始化临时值。

从句法上讲,它是“显式类型转换(函数式)”的特例;但是将该术语用于除类型转换之外的任何内容都会相当混乱。

在这个例子中,我会说i 是:(构造的?初始化的?吃错了吗?)

已初始化。如果您想更具体,列表初始化(带有空列表)、值初始化或零初始化。

【讨论】:

  • @gldraphael:整个类对象初始化为零,其作用是将_bar初始化为零。
  • @JonathanMee:I don't。也许您的编译器没有根据标准对对象进行值初始化。
  • @JonathanMee:你的编译器坏了:connect.microsoft.com/VisualStudio/feedback/details/484295
  • @JonathanMee:不,这是正确的做法。第一个是默认初始化的,留下一个不确定的值;第二个是正确的零初始化。
  • @JonathanMee 可以测试here,在vc2015中成功修复
【解决方案2】:

int() 的作用如下(请记住,在语法上,int 是一个简单类型说明符):

[C++11: 5.2.3/1]: simple-type-specifier (7.1.6.2) 或 typename-specifier (14.6) 后跟一个带括号的 expression-list em> 构造一个给定表达式列表的指定类型的值。如果表达式列表是单个表达式,则类型转换表达式等效于(在定义上,并且如果在含义上定义)对应的强制转换表达式(5.4)。如果指定的类型是类类型,则类类型应该是完整的。如果表达式列表指定了多个值,则类型应为具有适当声明的构造函数(8.5、12.1)的类,并且表达式T(x1, x2, ...) 等效于声明T t(x1, x2, ...);对于一些发明的临时变量t,结果是t的值作为prvalue。

通俗地说,它代表了一个带有空初始化器的临时int 的构造。不过,我认为你很难为整个构造找到一个正式的名称。

这与int i{} 不同,后者是具有初始化程序的命名对象的完整声明:您的i 已被声明、构造和初始化。

(我认为这与 Loki 在对该链接答案的评论中所说的话无关。)

【讨论】:

  • Uhm... 你几乎成功了,除了更好的引用是下一段:*表达式T(),其中T 是单一类型说明符...创建指定类型的prvalue,它是value-initialized *
【解决方案3】:

如果需要,您可以将其称为伪构造函数,以反映析构函数的术语(伪析构函数调用在 C++11 §5.2.4 中讨论)。反正int()int类型的默认值,即0。

关于“原始类型没有构造函数”的断言,这是一个相当愚蠢和不切实际的观点。从形式的角度来看,原始类型没有构造函数,但是那些坚持该断言的人根本就没有那么喜欢形式。此外,从机器代码的角度来看,它们不是,但是对于那些认为断言很重要的人来说,机器代码就像魔术一样。但是,有一个区别,即从机器代码的角度来看,常见的非原始 POD 类型也可能缺少构造函数(它们确实有正式的构造函数),我再次怀疑那些提出该断言的人是否意识到问题,即我认为他们没有资格发表意见。对于任何绝对的术语声明,您几乎可以肯定的是:当您听到这样的声明时,您几乎可以肯定,提出它的人几乎不知道所涉及的内容,并且该声明是不切实际和愚蠢的。

相反,当您听到例如在原始类型的上下文中“构造”或“构造函数调用”,想想它有意义地可能意味着什么。形式只是定义问题。重要的是,除了语言律师讨论,无论如何它是给定的,是有一个有效的概念模型。


综上所述,表达式T() 不是形式上的“构造函数”,它不是机器代码级别的构造函数,在任何有意义的概念模型中也不是概念上的构造函数。

可以是一个构造函数调用(实际上默认构造函数的定义是它可以在源代码级别被调用, 不带参数),但请注意构造函数调用没有语法类别。

考虑到以上所有,我将其称为构造函数调用,当需要更精确时,对于基本类型T,我将其称为伪构造函数调用强>。


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


请注意,关于您的陈述

它被反复强调原始类型没有构造函数。例如,当我调用Foo()时,此条未初始化为0

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

关于没有初始化器的原始类型的局部自动变量通常缺乏初始化,对于没有用户定义的构造函数的任何类型,您都会遇到相同的情况,即使有一个使用定义的构造函数,如果该构造函数没有初始化事物.

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

【讨论】:

  • @anonymous dowvoter:请公开表达您的不同意见,以便我可以向您展示您的想法错误。不知道我能不能救你,但我会努力的。 :)
  • @Cheersanhth.-Alf 我不确定我是否理解您的上次编辑:“对于没有用户定义构造函数的任何类型,您都有相同的情况”您能详细说明一下吗?
  • @JonathanMee:我指的是本地未初始化的情况。对不起。我澄清了(OP的错误断言对此造成了严重破坏,我没有看到他的Foo是那种类型)。
  • 在阅读您和Mike Seymour 的 cmets 之前,我真的不明白就默认 ctor 而言“值初始化”是什么意思。
  • @anonymous downvoter:这就像没有解释的 3 次反对票。我们应该进行决斗。请直播,我会看的。
猜你喜欢
  • 1970-01-01
  • 2014-09-30
  • 2016-02-26
  • 1970-01-01
  • 2011-03-15
  • 2011-01-26
  • 1970-01-01
  • 1970-01-01
  • 2015-06-17
相关资源
最近更新 更多