首页 > 试题广场 >

以下代码共调用多少次拷贝构造函数:

[单选题]
以下代码共调用多少次拷贝构造函数:
Widget f(Widget u){  
   Widget v(u);
   Widget w = v;
   return w;
}
main(){
    Widget x;
    Widget y = f(f(x));
}
  • 9
  • 3
  • 5
  • 7
啥头像

答案为 D

y=f(f(x)) 有两层 f() ,为了说明过程,把里面的一层标明为 f_1 ,外面一层标明为 f_2 。则 7 次调用分别是:
                              x  ->  f_1 u

f_1 u  ->  f_1 v

f_1 v  ->  f_1 w

f_1 w  ->  f_2 u

f_2 u  ->  f_2 v

f_2 v  ->  f_2 w

f_2 w  ->  y

编辑于 2015-08-13 15:57:24 回复(17)
这道题目咋一看,觉得是调用了9次,而不是7次。可是实际运行发现确实只调用了7次。为什么呢?


我理解9次的原因在这里:形参u,局部变量v和w,return返回w这里还是有一次拷贝构造函数的调用的。你想,函数返回之后局部变量要被销毁,所以在返回之前必定有会新建一个临时对象出来,这时必然会再调用一次拷贝构造函数,这样分析,这个一个f()函数就调用了4次拷贝构造函数,2次调用再加上主函数中给y的实例化,一共是9次才对!

从结果可以看出。我的分析肯定是错误的,错误发生在什么地方呢,我把主函数的调用注释掉,换一个写法,看结果再分析,再看这个运行图。




结果是一样的,都调用了7次。按上面的分析应该少 1 次(给 y实例化的那一次调用),这个问题的关键

就是出在这个return返回局部对象这里。通过单步调试,我发现是这么一回事:return之后一定会调用拷贝构造函数,这个返回的局部变量估计是编辑器直接优化给y了,和下一次的调用形参u。所以这里少了两次。(单步调试可以看得很清楚。)

拷贝构造函数调用的时机:
1、当用类的一个对象初始化该类的另一个对象时
2、 如果函数的形参是类的对象,调用函数时,进行形参和实参结合时. 
3、如果函数的返回值是类的对象,函数执行完成返回调用者时. 
4、需要产生一个临时类对象时

发表于 2015-08-19 22:25:25 回复(20)
出这种题的意义不大,可以在g++下做个试验 ,十有***要小于7次, 因为现在编译器几乎都会对return object做优化处理, Return Value Optimize
发表于 2015-08-13 22:03:41 回复(7)
1,可能有朋友对Widget w = v;有疑惑。
这里的 = 号,是v去初始化w。对象的初始化当然是去调用构造函数了,而不是重载的=运算符。
如果,
Widget w; 
w = v;
那么此时,= 号调用的是Widget operator=(const Widget& )赋值函数。因为 Widget w;已经把w初始化过了。

2,单个的 f(x) 执行时,会调用4次copy constructer.
本题中,f(x)的返回值直接又作了f()的参数。f(f(x))的返回值又去初始化y, 共7次
编辑于 2016-09-28 15:56:02 回复(2)
拷贝构造函数主要在以下三种情况下起初始化作用:

1. 在声明语句中用一个对象初始化另一个对象;

2. 将一个对象作为参数按值调用方式传递给另一个对象时生成对象副本;

3. 生成一个临时对象作为函数的返回结果。
调用顺序:
Widget u;
 Widget v(u);
Widget w=v;
return w;
Widget v(u);
Widget w=v;
return w;
编辑于 2015-12-10 15:20:45 回复(4)
Widget v(u);调用一次
Widget w=v;调用一次
return w;调用一次
也就是说一次f(x)调用三次拷贝构造函数
两层的话就是6次
再加一次Widget y=f(f(x));
因此总共7次。


发表于 2017-09-08 15:34:36 回复(0)

总共调用7次拷贝构造函数,在实例化类对象a时调用的是构造函数,然后将实参a与形参w结合时会调用一次拷贝构造函数;初始化局部变量m时调用一次拷贝构造函数;给局部变量n赋值时调用一次;函数返回并与形参进行结合时再调用一次。所以第一次调用func()函数时调用了4次。在此调用时不需要再将实参与形参结合,直接初始化m调用一次,赋值n调用一次,函数返回赋值给b调用一次。所以第二次调用func()函数时调用了3次。
编辑于 2018-03-20 22:08:03 回复(0)
用一个对象构造另外一个对象的时候要么是用拷贝构造,要么是用运算符重载,如果对于存在,就用赋值运算符的重载,如果不存在,就用拷贝构造,
发表于 2015-08-19 11:09:35 回复(0)
这个函数在VC共被调了9次拷贝构造函数,因为编译器没有进行优化,而在Linux下调了实际调了九次,却只显示7次,是因为编译器优化了,把w=u和reture w当成一步了,可以在编译时加选项-fno-elide-constructors看完整结果
发表于 2015-12-01 00:07:51 回复(0)
cyt头像 cyt

拷贝构造函数什么时候调用?

1当用类的一个对象初始化该类的另一个对象时.例如:

C/C++ code

int  main(){   point A( 1 , 2 );   point B(A); //用对象A初始化对象B,拷贝构造函数被调用. }


2 如果函数的形参是类的对象,调用函数时,进行形参和实参结合时. 

C/C++ code

void  f(point p){}main(){   point A( 1 , 2 );   f(A); //函数的形参为类的对象时,当调用函数时,拷贝构造函数被调用. }

3 如果函数的返回值是类的对象,函数执行完成返回调用者时. 

C/C++ code

point g(){   point A( 1 , 2 );    return  A; //函数的返回值是类的对象,返回函数值时,调用拷贝构造函数. } void  main(){     point B;   B = g();}

发表于 2015-09-08 11:18:21 回复(2)
函数体内发生了两次copy,从实参到形参u也会发生一次,所以调用两次函数共发生6次copy,最后在复制给y,一共7次。
发表于 2015-10-28 10:20:28 回复(0)
拷贝初始化发生情况:
1、使用=定义变量
2、将一个对象作为实参传递给一个非引用类型的形参
3、从一个返回类型为非引用的函数返回一个对象
4、用花括号列表初始化一个数组中的元素或一个聚合类中的成员
本题中:
=:3次
作为实参传递给非引用形参:2次
返回类型为非引用:2次
发表于 2018-09-29 13:40:24 回复(0)
vc6.0测试执行九次,,返回值return w,,返回的是值,,会建立一个临时变量,会调用拷贝构造函数。如果编译器不优化执行9次
发表于 2015-08-30 16:41:46 回复(1)
发表于 2015-08-17 08:44:09 回复(2)
临时变量返回应该有一次,编译器会优化,关了应该就是9次
发表于 2024-06-12 19:49:17 回复(0)
3+3+1;注意拷贝构造和赋值的调用时机的区别是前者是用一个已存在的对象创建一个新的对象,后者是已经有两个对象了,用其中一个为另一个赋值:f中的Widget w = v;
编辑于 2023-12-31 11:12:11 回复(0)
忘记了函数的返回值也调用了
发表于 2023-10-19 15:22:11 回复(0)
  1. 使用一个对象初始化另一个对象时,会调用拷贝构造函数。例如:

     MyClass obj1;  // 创建一个对象 obj1  MyClass obj2(obj1);  // 使用 obj1 初始化 obj2,调用 obj1 的拷贝构造函数
  2. 将对象作为函数参数按值传递时,会调用拷贝构造函数。例如:

     void foo(MyClass obj);  // 以值传递方式传递参数 obj,会调用拷贝构造函数  MyClass obj1;  foo(obj1);  // 调用 foo 函数,传递 obj1 的拷贝给函数参数 obj
  3. 在函数返回值时,会调用拷贝构造函数。例如:

     MyClass createObject() {     MyClass obj;  // 创建一个局部对象 obj     return obj;  // 返回局部对象 obj 的拷贝,会调用拷贝构造函数  }  MyClass obj2 = createObject();  // 调用 createObject 函数,并将返回值拷贝给 obj2
  4. 声明一个新对象时,用一个已经存在的对象来赋值,会调用拷贝构造函数。例如:

     MyClass obj1;  // 创建一个对象 obj1  MyClass obj2 = obj1;  // 使用 obj1 进行拷贝初始化,调用 obj1 的拷贝构造函数

以上是一些典型的情况,会触发拷贝构造函数的调用。在这些情况下,拷贝构造函数用于创建一个新的对象,并将原始对象的值传递给新对象。

发表于 2023-08-25 10:34:48 回复(0)
widget w=v属于对象的初始化自然需要调用构造函数,也就是每次f( x)需要调用三次,两次f(x)也就是六次 最后一次是外层的f( x)的返回值赋给了y,也算一次,也就是七次
发表于 2023-07-18 20:43:39 回复(0)
vs2022只有五次调用
发表于 2023-03-16 17:18:31 回复(0)