构造函数被多次调用

时间:2015-07-08 18:33:34

标签: c++

我编写了以下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。

3 个答案:

答案 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

http://ideone.com/fAjoA4

如果您不希望构造函数在分配时调用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作为输入,因此编译器可以使用以下内容从intB执行隐式转换。临时对象。

这就是为什么你看到你的构造函数被调用了三次 - 这两个赋值创建了临时B对象。