我编写了以下c ++代码,试图理解c ++中的copy elision。
#include <iostream>
using namespace std;
class B
{
public:
B(int x ) //default constructor
{
cout << "Constructor called" << endl;
}
B(const B &b) //copy constructor
{
cout << "Copy constructor called" << endl;
}
};
int main()
{
B ob =5;
ob=6;
ob=7;
return 0;
}
这会产生以下输出:
Constructor called
Constructor called
Constructor called
我无法理解为什么构造函数被调用三次,每次赋值给ob。
答案 0 :(得分:5)
B ob = 5;
这使用给定的构造函数。
OB = 6;
这使用给定的构造函数,因为没有if (fileName != "") {
System.out.println("Getting file");
String root = getServletContext().getRealPath("/");
File path = new File(root + "/IT/uploads");
System.out.println("Got path:" + path);
if (!path.exists()) {
boolean status = path.mkdirs();
}
File uploadedFile = new File(path + "/" + fileName);
System.out.println("Set UploadedFile:" + uploadedFile);
//File uploadedFile = new File(path + "/" + Title.replaceAll("\\s","") +"_"+ fileName);
filePath = uploadedFile.getAbsolutePath();
item.write(uploadedFile); // File has been uploaded to server
System.out.println("File Uploaded:" + uploadedFile);
fl[loopCount] = filePath.toString();
} else {
//System.out.print("No file has been detected, clearing out variable");
filePath = null;
}
loopCount++;
函数,B& operator=(int)
必须转换为6
类型。执行此操作的一条路径是临时构建B
并在分配中使用它。
OB = 7;
与上述答案相同。
我无法理解为什么每次赋值都会对构造函数进行三次调用
如上所述,您没有B
函数,但编译器很乐意为您automatically提供一个复制赋值运算符(即B& operator=(int)
)。正在调用编译器生成的赋值运算符,它采用B& operator=(const B&);
类型,并且所有B
类型都可以转换为int
类型(通过您提供的构造函数)。
注意:您可以使用B
(即explicit
)禁用隐式转化,我建议使用explicit B(int x);
,但隐式转化时除外是理想的。
explicit
注意:使用Visual Studio 2013(发布)编译
#include <iostream>
class B
{
public:
B(int x) { std::cout << "B ctor\n"; }
B(const B& b) { std::cout << B copy ctor\n"; }
};
B createB()
{
B b = 5;
return b;
}
int main()
{
B b = createB();
return 0;
}
这表明复制构造函数被省略了(即B ctor
函数中的B
实例被触发但没有其他构造函数。)
答案 1 :(得分:4)
每次为类型ob
的变量B
的实例分配一个整数值时,基本上构造一个B
的新实例,从而调用构造函数。想一想,如果没有通过构造函数将B
作为参数,编译器如何知道如何创建int
的实例?
如果您为班级B
重置了int
的作业运算符,则会调用它:
B& operator=(int rhs)
{
cout << "Assignment operator" << endl;
}
这将导致第一行:B ob = 5;
使用构造函数,而下面两个将使用赋值运算符,请亲自看看:
Constructor called
Assignment operator
Assignment operator
如果您不希望构造函数在分配时调用int
,则可以像这样声明它explicit
:
explicit B(int x)
{
cout << "Constructor called" << endl;
}
这会导致编译器出错,因为不再允许从整数隐式构造B
的实例,而是必须明确地完成,如下所示:
B ob(5);
另外,构造函数以int
为参数,不是默认构造函数,默认构造函数是可以不带参数调用的构造函数。
答案 2 :(得分:2)
您没有考虑赋值运算符。由于您尚未定义自己的operator=()
实现,因此编译器会生成默认的operator=(const B&)
实现。
因此,您的代码有效地执行以下逻辑:
#include <iostream>
using namespace std;
class B
{
public:
B(int x) //custom constructor
{
cout << "Constructor called" << endl;
}
B(const B &b) //copy constructor
{
cout << "Copy constructor called" << endl;
}
B& operator=(const B &b) //default assignment operator
{
return *this;
}
};
int main()
{
B ob(5);
ob.operator=(B(6));
ob.operator=(B(7));
return 0;
}
编译器生成的operator=()
运算符需要B
个对象作为输入,但您要传递int
值。由于B
有一个非explicit
构造函数,它接受int
作为输入,因此编译器可以使用以下内容从int
到B
执行隐式转换。临时对象。
这就是为什么你看到你的构造函数被调用了三次 - 这两个赋值创建了临时B
对象。