C++ 分配给匿名实例中基元类型的默认构造函数
考虑以下代码:C++ 分配给匿名实例中基元类型的默认构造函数,c++,c++11,C++,C++11,考虑以下代码: #include <iostream> template<class T> void f(T& t) { t = T(); } int main() { int x = 42; f(x); std::cout << x; } #包括 模板 空f(T&T) { t=t(); } int main() { int x=42; f(x); std::cout代码中没有“默认构造函数”。只有类类型可以有构造
#include <iostream>
template<class T>
void f(T& t)
{
t = T();
}
int main()
{
int x = 42;
f(x);
std::cout << x;
}
#包括
模板
空f(T&T)
{
t=t();
}
int main()
{
int x=42;
f(x);
std::cout代码中没有“默认构造函数”。只有类类型可以有构造函数。标量类型没有构造函数,默认或其他
T()
语法创建一个由所谓的值初始化初始化的临时对象。值初始化只解析为类类型的构造函数调用,并且只解析为具有用户定义构造函数的类类型的构造函数调用(在C++11中有一些细微差别)。对于其他类型,值初始化根本不涉及任何构造函数。它按照自己的特定且相当详细的初始化规则进行,直接定义数据的初始值,而不涉及任何构造函数(见语言规范中的8.5)
对于标量类型值初始化初始化零初始化。这就是为什么代码保证输出零。抽象初始化过程的确切细节在C++语言标准版本之间发生变化,但是自从C++语言开始保证<代码>T==int的表达式计算为零。也就是说,即使在C++98中,您的代码也将输出零
这是一个常见的误解,即所有这些T(…)
表达式都必然暗示构造函数调用。实际上,T(…)
表达式是一个函数强制转换表达式(无论参数的数量如何)(见语言规范中的5.2.3),它可能在某些特定情况下解析为构造函数调用,而在其他情况下与任何构造函数无关
例如,此代码
struct S { int x, y; };
S s = S();
保证用零初始化s
(包括s.x
和s.y
),尽管类s
有一个默认构造函数
expression仍然可以完全忽略它,而是按照自己的规则工作。以下是关于您的问题的标准说明:
在8.5.第10段中:
初始值设定项为空括号集的对象,即(),应进行值初始化
在8.5.第7段中:
初始化T类型对象的值意味着:
- 如果T是用户提供构造函数(12.1)的(可能是cv限定的)类类型(第9条),则
调用T的默认构造函数(如果T没有可访问的默认值,则初始化是错误的)
建造商)
- 如果T是一个(可能是cv限定的)非联合类类型,没有用户提供的构造函数,那么对象
初始化为零,如果T的隐式声明的默认构造函数是非平凡的,则该构造函数是
打电话来
- 如果T是数组类型,则每个元素都初始化为值
- 否则,对象初始化为零。
因此,由于int
甚至不是类类型,它属于上一条规则,初始化为零,因此这是一个绝对正确的行为。基本类型没有默认构造函数。int i;i=int()
将导致i
为0。默认构造函数我指的是不带参数的构造函数。int()
调用的函数是什么?(标准中此函数的名称是什么?)它称为值初始化。它是函数强制转换表示法。没有“空操作”或“未定义的行为”必需。您的结论不正确。关键是,int
不是类类型,因此零初始化适用。这与用户提供的构造函数的存在或不存在无关。@MWid,还有“否则,对象为零初始化”部分。当然你是对的,但是你的重点有点误导。int
初始化为零是因为第四条规则,而不是第二条规则,因为它根本不是类类型。@Christian,是的,我确实选择了一些不好的措辞,我会编辑它。你答案的第一部分是误导性的。实际发生的情况是:如果T
是简单类型说明符(例如int
),然后表达式T()
创建类型为T
的prvalue,该值已初始化。(参见5.2.3显式类型转换).8.5 10与此问题无关。因此,在上一个示例中,S s2;
也会将s2.x
和s2.y
初始化为零?@Andrew Tomazos-Dethomling:不会。为什么它会?S s2;
不执行值初始化,因此s2
将包含垃圾。请注意,在C++03中在这种情况下,即使存在构造函数,也不会调用它(在这种情况下,构造函数仅为非POD类调用)。在C++11中,构造函数在概念上被调用,但由于它什么都不做,对象保持未初始化状态。也就是说,最终结果是相同的(垃圾在s2
),但概念行为在C++03和C++11之间是不同的。这似乎有点不一致。我一直认为T()
和T;
是同一件事,只是后者被命名了——但这似乎要复杂得多。@Andrew Tomazos-深究:不,从标准化时代开始(C++98)()
是初始值设定项的一种特殊形式。使用()
初始值设定项与完全不使用任何初始值设定项-这是两种完全不同的情况,具有完全不同的初始化行为。()
初始值设定项从C++98更改为C++03,从C++03更改为C++11,但其在基本情况下的功能始终相同。对于基本类型,()
始终强制零初始化,