C++ 复制初始化和直接初始化之间有区别吗?
假设我有这个函数:C++ 复制初始化和直接初始化之间有区别吗?,c++,initialization,C++,Initialization,假设我有这个函数: 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()); } 在每个分组中,这些语句是否相同?或者在某些初始化中是否有额外的(可能是可优化的)副本 我见过有人说这两件事。请引用文本作为证据。也请添加其他案例。作业不同于初
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());
}
在每个分组中,这些语句是否相同?或者在某些初始化中是否有额外的(可能是可优化的)副本
我见过有人说这两件事。请引用文本作为证据。也请添加其他案例。作业不同于初始化 以下两行都进行初始化。完成单个构造函数调用:
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;
}
#包括
使用名称空间std;
甲级{
公众:
A(){
cout赋值不同于初始化
以下两行都进行初始化。完成单个构造函数调用:
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;
}
#包括
使用名称空间std;
甲级{
公众:
A(){
cout这些情况中有很多都取决于对象的实现,因此很难给出具体的答案
考虑一下这个案例
A a = 5;
A a(5);
在这种情况下,假设一个合适的赋值运算符&初始化接受单个整数参数的构造函数,我如何实现所述方法会影响每一行的行为。然而,通常的做法是,其中一个在实现中调用另一个,以消除重复的代码(尽管在如此简单的情况下,没有真正的目的。)
<>编辑:如其他响应中提到的,第一行实际上将调用复制构造函数。将与赋值运算符相关的注释视为与单独赋值有关的行为。
也就是说,编译器如何优化代码将有它自己的影响。如果我让初始化构造函数调用“=”运算符,如果编译器没有进行优化,那么顶行将执行2次跳转,而不是底行中的一次跳转
现在,对于最常见的情况,您的编译器将在这些情况下进行优化,并消除此类低效。因此,您所描述的所有不同情况实际上都是相同的。如果您想确切了解正在执行的操作,可以查看编译器的目标代码或程序集输出。许多se案例取决于对象的实现,因此很难给出具体的答案
考虑一下这个案例
A a = 5;
A a(5);
在这种情况下,假设一个合适的赋值运算符&初始化接受单个整数参数的构造函数,我如何实现所述方法会影响每一行的行为。然而,通常的做法是,其中一个在实现中调用另一个,以消除重复的代码(尽管在如此简单的情况下,没有真正的目的。)
<>编辑:如其他响应中提到的,第一行实际上将调用复制构造函数。将与赋值运算符相关的注释视为与单独赋值有关的行为。
也就是说,编译器如何优化代码将有它自己的影响。如果我让初始化构造函数调用“=”运算符,如果编译器没有进行优化,那么顶行将执行2次跳转,而不是底行中的一次跳转
现在,对于最常见的情况,您的编译器将在这些情况下进行优化,并消除此类低效。因此,您所描述的所有不同情况实际上都是相同的。如果您想确切了解正在执行的操作,可以查看编译器的目标代码或程序集输出。doubleb1=0.5;
是构造函数的隐式调用
双b2(0.5);
是显式调用
查看以下代码以查看差异:
#include <iostream>
class sss {
public:
explicit sss( int )
{
std::cout << "int" << std::endl;
};
sss( double )
{
std::cout << "double" << std::endl;
};
};
int main()
{
sss ddd( 7 ); // calls int constructor
sss xxx = 7; // calls double constructor
return 0;
}
#包括
类sss{
公众:
显式sss(int)
{
std::cout双b1=0.5;
是构造函数的隐式调用
双b2(0.5);
是显式调用
查看以下代码以查看差异:
#include <iostream>
class sss {
public:
explicit sss( int )
{
std::cout << "int" << std::endl;
};
sss( double )
{
std::cout << "double" << std::endl;
};
};
int main()
{
sss ddd( 7 ); // calls int constructor
sss xxx = 7; // calls double constructor
return 0;
}
#包括
类sss{
公众:
显式sss(int)
{
std::cout第一个分组:它取决于A_factory_func
返回的内容。第一行是复制初始化的示例,第二行是直接初始化。如果A_factory_func
返回一个A
对象,那么它们是等价的,它们都调用A
的复制构造函数,否则第一个版本对于返回类型为A\u factory\u func
或相应的A
构造函数,sion从可用的转换运算符创建类型为A
的右值,然后调用复制构造函数从该临时构造函数构造a1
。第二个版本尝试找到一个合适的构造函数,该构造函数接受的任何内容e> _factory_func
返回,或获取返回值可以隐式转换为的内容
第二个分组:逻辑完全相同,只是内置类型没有任何外来构造函数,所以实际上它们是相同的
第三组:c1
默认初始化,c2
从临时初始化的值复制初始化。如果用户提供了默认构造函数(如果有的话),则具有pod类型的c1
的任何成员(或成员的成员等)都可能不会初始化不要显式初始化它们。对于c2
,这取决于是否有用户提供的复制构造函数,以及该构造函数是否适当地初始化了这些成员,但是临时的成员都将被初始化(如果没有显式初始化,则初始化为零).正如litb所指出的,c3
是一个陷阱。它实际上是一个函数声明。第一组:它取决于什么是工厂函数
B(A const&)
B(A const&)
operator B(A&);
class A
{
A(int) { } // converting constructor
A(int, int) { } // converting constructor (C++11)
};
class B
{
explicit B(int) { }
explicit B(int, int) { }
};
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