提问人:synaptik 提问时间:9/27/2013 最后编辑:synaptik 更新时间:9/27/2013 访问量:131
班级成员在复制构造或按作业复制后出现乱码(有时)
Class members garbled after copy-construction or copy by assignment (sometimes)
问:
我的类表示一个正态分布的随机变量。默认情况下,实例正态分布,均值为 0 和 stdev 1(即标准正态随机变量)。NRRanNormal
有时,当我复制对象时,复制到(或通过复制构造函数构造)的对象的平均值和标准是乱码和无意义的。我很难找到这种乱码的原因。NRRanNormal
出于测试目的,以下函数显示给定对象的平均值和 stdev:NRRanNormal
void go(NRRanNormal& rv, const string label) {
std::cout << label << "\n"
<< "Mean: " << rv.getMean() << "\n"
<< "Stdev: " << rv.getStdev() << "\n\n";
}
现在,让我们看看在以下 4 种情况下会发生什么:
NRRanNormal foo;
go(foo, "foo");
NRRanNormal bar1 = foo;
go(bar1, "bar1");
NRRanNormal bar2;
bar2 = foo;
go(bar2, "bar2");
NRRanNormal bar3(foo);
go(bar3, "bar3");
上述语句的输出如下:
foo
Mean: 0
Stdev: 1
bar1
Mean: 5.55633e-317
Stdev: 6.95332e-310
bar2
Mean: 0
Stdev: 1
bar3
Mean: 0
Stdev: 0
正如你所看到的,简单地实例化一个对象()就可以按预期工作。foo
现在,当我这样做时,对象是乱码。但是,当我这样做时,对象不会乱码。这让我感到困惑。我以为像这样的语句块NRRanNormal bar1 = foo;
bar1
NRRanNormal bar2; bar2 = foo;
bar2
MyClass A;
MyClass B = A;
实际上由编译器转换为语句块
MyClass A;
MyClass B;
B = A;
因此,除非我刚才在上面写的是不正确的,否则似乎并且应该具有完全相同的成员值。但是,正如您从上面粘贴的输出中看到的那样,是乱码,而很好。bar1
bar2
bar1
bar2
这怎么可能?
您还会注意到这是乱码。我不确定这是同一个问题,还是另一个问题。bar3
下面是接口和实现的简化版本:NRRanNormal
class NRRanNormal {
public:
NRRanNormal();
~NRRanNormal();
NRRanNormal(const NRRanNormal& nrran);
NRRanNormal& operator= (const NRRanNormal& nrran);
double getMean() const;
double getStdev() const;
long getSeed() const;
private:
double m_mean, m_stdev;
long m_seed;
Normaldev* stream; // underlying C struct RN generator
};
NRRanNormal::NRRanNormal() { // by default, N(0,1)
m_mean = 0.0;
m_stdev = 1.0;
m_seed = 12345L;
stream = new Normaldev(m_mean, m_stdev, m_seed);
}
NRRanNormal::~NRRanNormal() { delete stream; }
NRRanNormal::NRRanNormal(const NRRanNormal& nrran) {
stream = new Normaldev(nrran.getMean(),nrran.getStdev(),nrran.getSeed());
*stream = *(nrran.stream);
}
NRRanNormal& NRRanNormal::operator= (const NRRanNormal& nrran) {
if(this == &nrran)
return *this;
delete stream;
stream = new Normaldev(nrran.getMean(),nrran.getStdev(),nrran.getSeed());
*stream = *(nrran.stream);
return *this;
}
double NRRanNormal::getMean() const { return m_mean; }
double NRRanNormal::getStdev() const { return m_stdev; }
long NRRanNormal::getSeed() const { return m_seed; }
该结构来自 Numerical Recipes 3d Edition。Normaldev
我的复制赋值运算符或复制构造函数有问题吗?
这里是,剥离了专有计算。Normaldev
typedef double Doub;
typedef unsigned long long int Ullong;
typedef unsigned int Uint;
struct Ranq1 {
Ullong v;
Ranq1(Ullong j) : v(/* some long number here */) {
/* proprietary calculations here */
}
inline Ullong int64() {
/* proprietary calculations here */
}
inline Doub doub() { /* proprietary calculations here */ }
inline Uint int32() { return (Uint)int64(); }
};
struct Normaldev : Ranq1 {
Doub mu,sig;
Normaldev(Doub mmu, Doub ssig, Ullong i):
Ranq1(i), mu(mmu), sig(ssig){}
Doub dev() {
/* proprietary calculations here */
}
};
答:
这是你的问题
NRRanNormal::NRRanNormal(const NRRanNormal& nrran) {
stream = new Normaldev(nrran.getMean(),nrran.getStdev(),nrran.getSeed());
*stream = *(nrran.stream);
}
应该是
NRRanNormal::NRRanNormal(const NRRanNormal& nrran) :
m_mean(nrran.m_mean),
m_stdev(nrran.m_stdev),
m_seed(nrran.m_seed)
{
stream = new Normaldev(nrran.getMean(),nrran.getStdev(),nrran.getSeed());
*stream = *(nrran.stream);
}
复制构造函数无法复制 mean、stddev 和 seed。您的赋值运算符有同样的问题
NRRanNormal& NRRanNormal::operator= (const NRRanNormal& nrran) {
if(this == &nrran)
return *this;
m_mean = nrran.m_mean;
m_stdev = nrran.m_stdev;
m_seed = nrran.m_seed;
delete stream;
stream = new Normaldev(nrran.getMean(),nrran.getStdev(),nrran.getSeed());
*stream = *(nrran.stream);
return *this;
}
我猜你太专注于课堂上棘手的指针,以至于忘记了基本的东西。
顺便说一句代码
MyClass A;
MyClass B = A;
实际上被编译器转换为
MyClass A;
MyClass B(A);
换句话说,调用复制构造函数(假设 A 和 B 是同一类型)。MyClass B = A;
评论
stream = new Normaldev(nrran.getMean(),nrran.getStdev(),nrran.getSeed());
stream = new Normaldev(m_mean,m_stdev,m_seed);
评论
new
stream
new
delete
stream