为什么在下面的代码中调用析构函数?

Hei*_*erg 2 c++

请考虑以下代码.此代码取自面向对象的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次?这段代码错了吗?

Yan*_*ang 8

当您致电时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.


cod*_*ing 5

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).如果要防止这种情况发生,请explicitvc(int a[])构造函数上使用关键字.

事后的想法:我最初的答案并没有真正回答最后提出的主要问题(为什么析构函数被调用三次).我想其他人已经很好地回答了这个问题:一个vc对象是在你的内部本地创建的,operator*因为你在那里通过参数传递值.

现在你可以问为什么析构函数实际上没有被调用5次(对于隐式创建的对象也是2次).我想这是因为编译器以某种方式优化了新对象的实际创建(可能是返回值优化,如果我错了,有人请纠正我!).