请考虑以下代码.此代码取自面向对象的C++编程一书 ! - 第12章模板.
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
class vc
{
int size2;
int *v;
public :
vc(int size1);
vc(int *a);
~vc()
{
printf("\n calling destructor");
}
int operator *(vc );
};
vc::vc(int size1)
{
v = new int[size2=size1];
for(int i=0;i<this->size2;i++)
v[i]=0;
}
vc::vc(int a[])
{
for(int i=0;i<this->size2;i++)
{
v[i]=a[i];
}
}
int vc::operator *(vc v1)
{
int total=0;
for(int i=0;i<size2;i++)
total+=(v[i]*v1.v[i]);
return total;
}
int main()
{
int a[3]={1,2,3};
int b[3]= {5,6,7};
vc v1(3),v2(3);
v1=a;
v2=b;
int total = v1*v2;
cout << total;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
首先,这些代码无法正常工作.它应该显示38作为输出.当我开始调试此代码时,我发现在此行之后3被分配.但是在执行下一行时,控制权将传递给第二个构造函数并显示垃圾值.此外,析构函数在行后调用,同样在下一行之后发生.size2vc v1(3),v2(3);size2v1=a
calling destructor
calling destructor
calling destructor0
为什么析构函数会被调用3次?这段代码错了吗?
当您致电时v1*v2,您将v2转到该方法
int vc::operator *(vc v1)
Run Code Online (Sandbox Code Playgroud)
它创建了一个本地副本v2.因此,您有一个额外的vc实例.
你第一个怀疑的答案,
但是在执行下一行时,控制权被传递给第二个构造函数,而size2显示一个垃圾值,并且它不执行三次.
是因为
v1 = a;
Run Code Online (Sandbox Code Playgroud)
vc通过调用vc::vc(int a[])并将其分配给临时创建临时v1.但是,此构造函数未初始化size2.所以你得到了垃圾价值.
更简洁的方法是传递数组及其大小:
vc::vc(int a[], int size1) {
v = new int[size2=size1];
for(int i=0; i<size2; i++)
v[i] = a[i];
}
int main()
{
int a[3]={1,2,3};
int b[3]= {5,6,7};
vc v1(a, 3), v2(b, 3);
int total = v1*v2;
cout << total;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然后total将是38.
v1=a;
Run Code Online (Sandbox Code Playgroud)
那条线实际上不仅仅是一项任务.它是临时对象的构造,并将其分配给已创建的对象.分配int[]给编译器可以看到的类的唯一方法是使用vc(int a[])构造函数创建一个临时对象vc- 但是构造函数没有初始化size2,这就是你看到的问题("但是在执行下一行时,control被传递给第二个构造函数,size2显示一个垃圾值.").
创建此临时值后,隐式赋值运算符(由编译器自动为您创建,因为您未指定)将将此对象的成员复制到已创建的对象.
这称为隐式转换(请参阅此处:https://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fcplr384.htm).如果要防止这种情况发生,请explicit在vc(int a[])构造函数上使用关键字.
事后的想法:我最初的答案并没有真正回答最后提出的主要问题(为什么析构函数被调用三次).我想其他人已经很好地回答了这个问题:一个vc对象是在你的内部本地创建的,operator*因为你在那里通过参数传递值.
现在你可以问为什么析构函数实际上没有被调用5次(对于隐式创建的对象也是2次).我想这是因为编译器以某种方式优化了新对象的实际创建(可能是返回值优化,如果我错了,有人请纠正我!).