在学习c++过程中,我编了一个小程序,为了多练习些内容,里面用了类,现在是调试完事的程序,能满足我的要求,可是发现个问题,我认为一个无错的改动,可是显示结果却不一样,而且编译器并不抱错。我的编译ide是codeblocks。
//*************************
//成功后的程序,注意蓝色部分,是我更改后发现问题的地方
//*************************
#include <iostream>
#include <vector>
using namespace std;
//定义一个类,能实现 vector<unsigned>型的输出,和vector容器中奇数乘以2替换当前奇数
class vecnum
{
vector<unsigned> *i;
vector<unsigned>::iterator it;
public:
//构造函数,接受一个vector<unsigned>型的指针形参
vecnum(vector<unsigned> *n)
{
i=n;
}
//实现输出功能
void inputline()
{
for(it=i->begin();it!=i->end();++it)
cout<<*it<<" ";
cout<<endl;
}
//实现奇数*2后,替换当前奇数
void jishuan()
{
for(it=i->begin();it!=i->end();++it)
if(*it%2!=0) *it *=2;
}
~vecnum(){};
};
int main()
{
vector<unsigned> num1;
unsigned j;
//初始化vector容器
while(cin>>j)
{
num1.push_back(j);
}
vecnum vn(&num1);
vn.inputline();
vn.jishuan();
vn.inputline();
}
//输入 22 1 3 5 7 ctrl+z后 程序输出结果为
//22 1 3 5 7
//22 2 6 10 14
//将第一排的奇数*2,替换原先的
//************************************
//可是我用下面代码替换蓝色部分,我觉得完全是等价替换,为什么不行呢?
//构造函数,接受一个正常的vector<unsigned>型的形参
vecnum(vector<unsigned> n)//形参改为非指针形式了
{
i=&n;//接受形参n后,将i指向n
}
//并且在后面的构造函数调用中将vn(&num1)换成符合形式的vn(num1)
//编译没有问题,可同样输入
//输入 22 1 3 5 7 ctrl+z后
//程序输出结果为
//0 1 3 5 7
//0 2 6 10 14
//后面全对,可是为什么第一个数字变成0了呢,22哪里去了
//是不是我的概念有什么错误或者什么的,请高手指教。
//可是我用下面代码替换蓝色部分,我觉得完全是等价替换,为什么不行呢?
//构造函数,接受一个正常的vector<unsigned>型的形参
vecnum(vector<unsigned> n)//形参改为非指针形式了
{
i=&n;//接受形参n后,将i指向n
}
晕,你拿的是函数的参数的地址,这个是一个临时对象,用拷贝构造函数拷贝的原对象的一个副本(位于栈上),所以不是你原来的那个想要操作的对象的地址(换句话说,你拿到的是临时对象)
岂止是不一致,你竟然还输出了 0 1 3 5 7 ,这已经让我很惊讶了,因为事实上,应该抛异常。
我来给你解释下你的第二种方式:
1,vector<unsigned> num1; 这里为 num1 分配了一个地址 0x0027f8dc
2, vecnum vn(&num1); 这里比较复杂,&num1 就是 0x0027f8dc,在进入 vecnum(vector<unsigned> n) 之前,为行参赋值,使用拷贝构造方式 vecnum n(num1); 在这里 n 的地址是 0x0027f78c,与 num1 不同;
3,
vecnum(vector<unsigned> n)
{
i=&n; 行参 n 已经赋值完毕,同时 n 包含和 num1 同样的数组元素,&n 就等于 0x0027f78c,该取地址操作完毕后,i 就指向了 0x0027f78c,同时,这个时候, i 也包含和 num1 同样的数组元素;
}
4,出了构造函数后,问题就来了,形参 n 出栈被销毁,但是指针变量 i 的值仍然为 0x0027f78c,由于前面 n 被销毁,那么为 n 分配的vector<unsigned>类型的内存也可能被销毁掉,这里销毁就是指该内存区域可以被系统用于为其它目的分配内存使用;
5,指针这个东西很强大,强大就强大在你拿到后,系统都无法限制你的操作,虽然形参 n 已经被销毁,但是 i 却保留了内存地址 0x0027f78c,因此,如果此时,我们再把 i 当着 vector<unsigned> * 使用的时候,系统就会自动按照 vector<unsigned> 的内存结构从地址 0x0027f78c 开始为其内部变量取值。显然,这里发生了内存越界,但是系统无法检测出来。这在C++中很常见,比如 BYTE* pData = new BYTE[200]; 那么 pData[201] = 0x96; 仍然是正确的.
所以,你的第二种方式能够运行成功,我觉得是一种巧合,也可能和编译器有关,我使用 vs 2010 ,始终是无法成功,我总会得到一个 无限大的 vector。