在下面的代码中,我试图将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
答案 0 :(得分:2)
在
v1=x;
发生两件事:
vector
构建了一个全新的临时vector(T *a)
。此临时vector
与v1
无关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
和临时文件现在指向相同的内存分配,因此v
的v1
指向无效的内存。
需要一个赋值运算符来清除此混乱情况。有关编写赋值运算符的非常简单,非常安全的方法,请参见Copy and Swap Idiom。