假设我有这样一个函数:
void my_test()
{
A a1 = A_factory_func();
A a2(A_factory_func());
double b1 = 0.5;
double b2(0.5);
A c1;
A c2 = A();
A c3(A());
}
在每一组中,这些陈述是否相同?或者在某些初始化中是否存在额外的(可能是可优化的)副本?
我见过有人两种说法都说。请引用原文作为证明。也请添加其他案例。
当初始化一个对象时,你可以看到显式和隐式构造函数类型的区别:
类:
class A
{
A(int) { } // converting constructor
A(int, int) { } // converting constructor (C++11)
};
class B
{
explicit B(int) { }
explicit B(int, int) { }
};
在main函数中:
int main()
{
A a1 = 1; // OK: copy-initialization selects A::A(int)
A a2(2); // OK: direct-initialization selects A::A(int)
A a3 {4, 5}; // OK: direct-list-initialization selects A::A(int, int)
A a4 = {4, 5}; // OK: copy-list-initialization selects A::A(int, int)
A a5 = (A)1; // OK: explicit cast performs static_cast
// B b1 = 1; // error: copy-initialization does not consider B::B(int)
B b2(2); // OK: direct-initialization selects B::B(int)
B b3 {4, 5}; // OK: direct-list-initialization selects B::B(int, int)
// B b4 = {4, 5}; // error: copy-list-initialization does not consider B::B(int,int)
B b5 = (B)1; // OK: explicit cast performs static_cast
}
默认情况下,构造函数是隐式的,所以你有两种方法来初始化它:
A a1 = 1; // this is copy initialization
A a2(2); // this is direct initialization
通过将结构定义为显式,你只有一种方式是直接的:
B b2(2); // this is direct initialization
B b5 = (B)1; // not problem if you either use of assign to initialize and cast it as static_cast
First grouping: it depends on what A_factory_func returns. The first line is an example of copy initialization, the second line is direct initialization. If A_factory_func returns an A object then they are equivalent, they both call the copy constructor for A, otherwise the first version creates an rvalue of type A from an available conversion operators for the return type of A_factory_func or appropriate A constructors, and then calls the copy constructor to construct a1 from this temporary. The second version attempts to find a suitable constructor that takes whatever A_factory_func returns, or that takes something that the return value can be implicitly converted to.
第二组:逻辑完全相同,只是内建类型没有任何奇异构造函数,因此它们实际上是相同的。
Third grouping: c1 is default initialized, c2 is copy-initialized from a value initialized temporary. Any members of c1 that have pod-type (or members of members, etc., etc.) may not be initialized if the user supplied default constructors (if any) do not explicitly initialize them. For c2, it depends on whether there is a user supplied copy constructor and whether that appropriately initializes those members, but the members of the temporary will all be initialized (zero-initialized if not otherwise explicitly initialized). As litb spotted, c3 is a trap. It's actually a function declaration.
很多情况都取决于对象的实现,所以很难给你一个具体的答案。
考虑一下这个案例
A a = 5;
A a(5);
在这种情况下,假设一个适当的赋值操作符和初始化构造函数接受一个单一的整数参数,我如何实现这些方法影响每一行的行为。然而,通常的做法是,其中一个在实现中调用另一个,以消除重复的代码(尽管在这样简单的情况下,没有真正的目的)。
编辑:正如在其他响应中提到的,第一行实际上将调用复制构造函数。将与赋值操作符相关的注释视为与独立赋值相关的行为。
也就是说,编译器如何优化代码会有它自己的影响。如果初始化构造函数调用“=”运算符——如果编译器不做任何优化,则顶部行将执行两次跳转,而底部行则执行一次跳转。
现在,对于最常见的情况,编译器将优化这些情况并消除这种低效率。所以实际上你所描述的所有不同情况都是一样的。如果您想确切地了解正在执行的操作,可以查看编译器的目标代码或汇编输出。
赋值不同于初始化。
以下两行代码都进行初始化。一个构造函数调用完成:
A a1 = A_factory_func(); // calls copy constructor
A a1(A_factory_func()); // calls copy constructor
但它不等于:
A a1; // calls default constructor
a1 = A_factory_func(); // (assignment) calls operator =
我现在还没有一篇文章来证明这一点,但这很容易实验:
#include <iostream>
using namespace std;
class A {
public:
A() {
cout << "default constructor" << endl;
}
A(const A& x) {
cout << "copy constructor" << endl;
}
const A& operator = (const A& x) {
cout << "operator =" << endl;
return *this;
}
};
int main() {
A a; // default constructor
A b(a); // copy constructor
A c = a; // copy constructor
c = b; // operator =
return 0;
}
就这部分回答:
A c2 = A();c3 (());
由于大多数答案都是c++11之前的,我补充了c++11必须说的:
A simple-type-specifier (7.1.6.2) or typename-specifier (14.6)
followed by a parenthesized expression-list constructs a value of the
specified type given the expression list. If the expression list is a
single expression, the type conversion expression is equivalent (in
definedness, and if defined in meaning) to the corresponding cast
expression (5.4). If the type specified is a class type, the class
type shall be complete. If the expression list specifies more than a
single value, the type shall be a class with a suitably declared
constructor (8.5, 12.1), and the expression T(x1, x2, ...) is
equivalent in effect to the declaration T t(x1, x2, ...); for some
invented temporary variable t, with the result being the value of t as
a prvalue.
所以不管优化与否,它们在标准上是等价的。
请注意,这与前面提到的其他答案是一致的。只是为了正确起见,引用了标准的内容。