考虑到成本,这些情况是否相同?
// case 1
int a = 5;
// case 2
int a (5);
// case 3
int a;
a = 5
Run Code Online (Sandbox Code Playgroud)
Dav*_*eas 16
这三种语法是不同的,当我使用用户定义的类型而不是int时,请耐心等待,稍后我会回到int.
T a(5); // Direct initialization
T b = 5; // Implicit conversion (5->tmp) + copy-initialization
T c; c = 5; // Default initialization + assignment
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,对象a是通过构造函数构造的,该构造函数接受一个int或者可以隐式转换的类型int.
struct T {
T( int ); // T a(5) will call this directly
};
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,类型的临时对象T是由创建隐式转换从int,然后将该临时被用来复制构建体 b.允许编译器优化代码并仅执行隐式转换来代替最终对象(而不是使用它来创建临时对象.但是必须验证所有限制:
class T {
T( T const & );
public:
explicit implicit T( int );
};
int main() {
T b = 5; // Error 1: No implicit conversion from int to T.
// Fix: remove the `explicit` from the constructor
// Error 2: Copy constructor is not accessible
}
Run Code Online (Sandbox Code Playgroud)
第三种情况是默认构造,然后是分配.对类型的要求是它可以是默认构造的(有一个没有参数的构造函数,或者根本没有用户定义的构造函数,编译器将隐式定义它).该类型必须可以从中分配,int或者必须存在从可以分配到int的类型的隐式转换.如您所见,树案例中的类型要求不同.UT
除了不同操作的语义之外,还有其他重要的区别,并非所有这些都可以在所有上下文中使用.特别是,在类的初始化列表中,您不能使用隐式转换+复制初始化版本,并且您只能使用默认构造+分配的前半部分.
// OK // error // ok but different
struct test { struct test { struct test {
T x; T x; T x;
test(int v) : x(v) {} test(int v) : x=5 {} test( int v ) {
x = v;
}
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,x使用值直接初始化属性v.第二种情况是语法错误.第三种情况首先默认初始化然后在构造函数的主体内部分配.
回到int示例,类型满足所有需求,因此编译器为这三种情况生成的代码几乎没有差异,但仍然无法使用int b = 5;初始化列表中的版本来初始化整数属性.此外,如果一个类的成员属性是一个常量整数,那么当它进入构造函数块时,你不能使用等价的int c; c =5;(上面的第三列)作为成员属性const,也就是说,x = v;上面会尝试修改一个常量并且编译器会抱怨.
至于每个人的成本,如果可以使用它们,它们int(对于任何POD类型)都会产生相同的成本,但对于具有默认构造函数的用户定义类型则不然,在这种情况下T c; c = 5;会产生成本的默认构造其次是成本分配.在另外两种情况下,标准明确声明允许编译器生成完全相同的代码(一旦检查了约束).
对于前两个,没有区别。
根据标准文档8.5.11,
初始化的形式(使用括号或=)通常无关紧要,但是当初始化程序或要初始化的实体具有类类型时,它就很重要。见下文。仅当要初始化的实体具有类类型时,带括号的初始化器才可以是表达式的列表。
第三个不是初始化,而是赋值。
考虑到成本
在前两种情况下,您将创建一个值为5的整数。
在第三种情况下,您将创建一个具有未定义值的整数,并将其替换为5。