使用转换构造函数进行类到类类型转换的程序崩溃

时间:2019-06-28 01:46:41

标签: c++ constructor type-conversion destructor

在下面的代码中,我试图将int *类型转换为vector类。但是在运行程序时,程序在转换构造函数中暂停后终止,将值从int[]复制到vector::int *v

这也是其中一本书的一个例子。我一直在试图弄清这里正在发生什么。任何线索都将有所帮助。

#include<iostream>

using namespace std;

const int size=3;

template <class T>
class vector{
    T*v;
    public:
        vector()
        {
            v=new T[size];
            for(int i=0; i<size; i++){
                cout << "A" << endl;
                v[i]=0;
            }
            cout << "vector 0-arg ctor" << endl;
        }
        vector(T *a) ///////////////////// conversion ctor for type conversion
        {
            for(int i=0; i<size; i++){
                cout << "B" << endl; 

                v[i]=a[i];////////////////// Program exits here 

            }
            cout << "vector 1-arg ctor" << endl;
        }
        T operator*(vector &y)
        {
            T sum=0;
            for(int i=0; i<size; i++){
                cout << "C" << endl;
                sum += this->v[i] * y.v[i];
            }
            return sum;
        }
};

int main(){
    int x[3]={1,2,3};
    int y[3]={4,5,6};
    vector <int> v1;
    vector <int> v2;

    v1=x; ////////////////////// Type conversion from int * -> vector
    v2=y; ////////////////////// int * -> vector

    int R=v1*v2;
    cout << "R : " << R << endl;
    return 0;
}

输出如下->

A
A
A
vector 0-arg ctor
A
A
A
vector 0-arg ctor
B

1 个答案:

答案 0 :(得分:2)

v1=x;

发生两件事:

  1. 使用vector构建了一个全新的临时vector(T *a)。此临时vectorv1无关
  2. 使用编译器生成的默认赋值运算符将临时vector分配给v1

不幸的是,vector(T *a)不会为v分配,也不会为v分配现有存储。由于v没有指向有效的对象,因此对其取消引用将调用Undefined Behaviour,并且可以执行任何操作。在询问者的计算机上,看来v[i]=a[i];写入无效的内存并导致崩溃。我们都那么幸运吗?

解决方案

v分配一些存储空间

vector(T *a): v(new T[size])
{
    for(int i=0; i<size; i++){
        cout << "B" << endl; 
         v[i]=a[i];
    }
    cout << "vector 1-arg ctor" << endl;
}

我以Member Initializer List为例。可悲的是,这是可悲的,并且非常有用。

不要尝试

vector(T *a): v(a)
{
}

尽管看起来很诱人。 vector析构函数没有办法在不久的将来的某个时候写入,以防止内存泄漏能够告诉静态分配的数组x,该数组不能为{{1} } ed,而不会调用默认构造函数提供的动态分配中的未定义行为,该行为必须进行delete ed。

而且由于出现了析构函数的话题,因此必须了解Rule of Three

delete的步骤2执行分配。编译器生成的默认赋值运算符非常简单且非常愚蠢。它将一个v1=x;中的内容精确复制到另一个。如果看到指针,它将复制地址,而不是所指向的地址。无论目标对象指向的是什么,都不会被vector修饰,并且很可能丢失。这样就剩下两个指向相同内存的对象。现在,更改一个对象可以更改另一个对象,并且随之而来。

此分配后,delete的{​​{1}}将被临时v1替换,从而泄漏v的原始内存分配。更糟糕的是,临时vector符合名称,并很快超出范围。一旦v1具有可正常运行的析构函数,临时文件将随同它的vector,并且由于vector和临时文件现在指向相同的内存分配,因此vv1指向无效的内存。

需要一个赋值运算符来清除此混乱情况。有关编写赋值运算符的非常简单,非常安全的方法,请参见Copy and Swap Idiom