我是C ++的新手,正在用它做一个物理项目。
我遇到了一个问题:
我创建了一个 Photon
类,其成员var名为 energy
(float)。
在循环(解析值的txt文件)中,当我创建新的 Photon
时,我会为其指定一个 energy
(作为一个字符串 - 我后来转换为浮点数)通过构造函数。
然后我将 photon
推入光子矢量。当 cout
创建 Photon
之后的能量时,它们就像预期的那样,并且正确对应于txt文件。
但是,在循环之后,当我再次循环光子矢量并打印photons[i].energy
时,值会奇怪地改变 - 其中一些甚至 {{1 }} !
NaN
有什么想法吗?
更新 - 光子课程:
void Event::addPhoton(string data) {
Photon p(data); // the string data is parsed in constructor
cout << "the energy: " << p.energy << " \n"; // energies output here are correct
photons.push_back(p);
// BUG somewhere here
cout << "Update: Just added a photon. Current photon energies: ***" << endl;
for (int i = 0; i < photons.size(); i++) {
cout << photons[i].energy << ", "; // here, values have changed !!
}
cout << endl;
}
答案 0 :(得分:4)
push_back
使用Photon
的复制构造函数,此时它似乎什么都不做,因此会导致Photon
随机初始化值。
如果您使用的是支持C ++ 11的编译器,则只需将其定义为
即可跳过实现Photon(const Photon&) = default;
在标题中,这告诉编译器您需要整个对象的完整副本。如果您没有定义一个,编译器将为您生成一个。但是有可读性的原因会鼓励使用默认值。
在这种特殊情况下,如果您的编译器支持C ++ 11,您可以随时使用emplace_back
并在向量中构建对象。
photons.emplace_back(data);
答案 1 :(得分:4)
您只想删除班级Photon::Photon(const Photon& orig) {}
的复制构造函数,它应该可以正常工作。
注意:您也可以删除析构函数,因为您可能不需要它。
注意2:默认的复制构造函数(如果删除你的,将自动生成)要求Photon
的成员要么可以轻易复制,要么自己拥有复制构造函数。
实际上,您的Photon
副本构造函数为空。因此,每个基本类型值或POD都是默认初始化的(使用随机值)。
标准说:
在非委托构造函数中,如果给定的非静态数据成员未由a指定 mem-initializer-id(包括没有mem-initializer-list的情况,因为构造函数没有ctor-initializer )并且该实体不是抽象类的虚基类(10.4) ,然后:
[...]
- 否则,该实体默认初始化。
默认情况下默认值是什么意思?
如果没有为对象指定初始化程序,则默认初始化该对象;如果没有执行初始化,具有自动或动态存储持续时间的对象具有不确定的值。
这意味着如果你没有为你的(复制)构造函数提供 member-initializer-list ,如果你没有在(copy)构造函数中指定有意义的值,你最终会有完成(复制)构造函数后的值中的垃圾。
因此,在行photons.push_back(p);
中,您将p复制到向量中,您将最终获得垃圾初始化条目。
所以我的建议如下:剥离以下函数并设计一个默认构造函数,为成员提供有意义的值。
删除:
Photon::Photon(const Photon& orig) {}
Photon::~Photon() {}
添加:
Photo::Photon (void) :
momentum(/*any value required by Momentum constructor*/),
energy(0.0)
{
}
您不需要析构函数,因为您不管理资源。因此,您也不需要提供复制构造函数,因为编译器只会为您复制一个将复制Photon类的每个成员的文件。
使用push_back
的示例应该可以使用,但是如果使用C ++ 11编译器,也可以使用emplace_back
,因为它只是将其参数“移交”给合适的构造函数。 / p>
而不是
Photon p(data); // the string data is parsed in constructor
photons.push_back(p);
你也可以
photons.emplace_back(data);
你不会在这里制作任何副本,因为矢量中的新对象将使用数据字符串构建。
Photon(const Photon&) = default;
我认为复制构造函数的显式默认值不是更具可读性,但如果您不希望它是公共的但受保护(甚至是私有),您可能希望明确默认它。
默认情况下,隐式构造函数,析构函数和赋值运算符是其类的inline public
成员。
答案 2 :(得分:3)
将对象插入向量时,(通常)使用对象的复制构造函数创建对象的副本。您的复制构造函数不执行任何操作,因此复制的光子的energy
值保持未初始化状态。要解决此问题,请将Photon
的复制构造函数复制到原始光子的energy
值上。
Photon::Photon(const Photon& orig): energy(orig.energy) {
// etc.
}
答案 3 :(得分:2)
您需要向我们提供产生错误的代码。
顺便说一句,能量成员应该漂浮。 如果您的输入源是文本文件,则在传递给Photon构造函数之前,应将能量值解析为浮点数(float或double)。
如果您只想实现成员复制,您甚至可以省略复制构造函数。 C ++编译器将为您生成一个。