在第二个扩展类中,当调用方法clone(s)的字段值正在改变时。
清单:
#include<iostream>
using namespace std;
class Set
{
public:
Set(int min,int max)
{
num_bits=max-min+1;
num_bytes=(num_bits+7)/8;
elems=new int8_t[num_bytes];
for(int i=0; i<num_bytes; i++)elems[i]=0;
minElem=min;
maxElem=max;
};
void add(int n)
{
int bit=n-minElem;
elems[bit/8]|=(1<<(bit%8));
};
void del(int n)
{
int bit=n-minElem;
elems[bit/8]&=~(1<<(bit%8));
};
bool has(int n)
{
int bit=n-minElem;
return(elems[bit/8]&(1<<(bit%8)));
}
void print()//str
{
int i=0;
do
{
cout<<(has(i+minElem)?"1":"0");
i++;
if(i%8==0)cout<<" ";
}
while(i<num_bits);
}
~Set()
{
delete[] elems;
};
public://rotected
int num_bits,num_bytes,minElem,maxElem;
int8_t *elems;
};
class ExSet:public Set{
public:
ExSet(int min,int max):Set(min,max){}
ExSet(Set s):Set(s.minElem,s.maxElem){/*clone(s);*/}
void clone(Set s){
//for(int i=0;i<num_bytes;i++){int x=s.elems[i];cout<<elems[i]<<'='<<s.elems[i]<<'/';}
};
};
main()
{
char *p="ABCZabxyz";
Set s('A','z');
do s.add(*p);
while(*++p!='\0');
s.del('B');
s.print();
cout<<endl;
for(char c='A'; c<='z'; c++)if(s.has(c))cout<<c;
cout<<endl;
//delete &s;
ExSet es(s);
for(char c='A'; c<='z'; c++)if(s.has(c))cout<<c;
};
预期:
10100000 00000000 00000000 01000000 11000000 00000000 00000001 11
ACZabxyz
ACZabxyz
得到:
10100000 00000000 00000000 01000000 11000000 00000000 00000001 11
ACZabxyz
FGINQRVWghqrvw
答案 0 :(得分:1)
您正在复制对象而未指定自定义复制构造函数。这会失败,因为您的Set类有一个指向堆对象的成员。该堆对象必须由客户副本构造函数复制,因为编译器提供的复制构造函数未正确复制它。
阅读有关定义副本构造函数以及深度与平面副本的信息。
答案 1 :(得分:0)
我认为你的问题在这里:
ExSet(Set s):Set(s.minElem,s.maxElem){/*clone(s);*/}
当您调用Set
的构造函数时,您将分配新数组:
elems=new int8_t[num_bytes];
并丢失指向以前数据的指针。 您应该创建一个正确的复制构造函数或更改现有的复制构造函数。
答案 2 :(得分:0)
以下行是您的记忆问题的来源。
ExSet(Set s):Set(s.minElem,s.maxElem){/*clone(s);*/}
执行时
ExSet es(s);
s
的临时副本是在ExSet
的构造函数的调用中创建的。当该临时值被破坏时,它会删除elems
所拥有的内存。
当s
被破坏时,再次删除相同的内存。这导致了不确定的行为。在您的情况下,它会产生错误的结果。在其他情况下,程序可能会崩溃。
您可以使用
解决此特定问题ExSet(Set const& s):Set(s.minElem,s.maxElem){/*clone(s);*/}
但是,要获得正确的修复,请在Set
中提供复制构造函数和复制赋值运算符。要了解原因,请查看Rule of Three。