我正在编写C ++代码来处理从实验室测量中填充的一组直方图。当我尝试更好地组织事情时,我遇到了问题,我认为我的问题来自错误处理指针和/或结构。
我原来的设计看起来像这样:
// the following are member variables
Histogram *MassHistograms[3];
Histogram *MomentumHistograms[3];
Histogram *PositionHistograms[3];
其中每个数组的元素0对应于一个实验室测量,每个元素的元素1对应于另一个,等等。我可以通过MassHistograms[0]
或类似的方式访问各个直方图,这样就可以了。然而,组织对我来说似乎不对 - 如果我要执行新的测量,我必须为每个直方图阵列添加一个元素。相反,我想出了
struct Measurement {
Histogram *MassHistogram;
Histogram *MomentumHistogram;
Histogram *PositionHistogram;
};
作为一个复杂的附加层,我还想根据对数据进行的处理来捆绑这些测量,所以我做了
struct MeasurementSet {
Measurement SignalMeasurement;
Measurement BackgroundMeasurement;
};
我认为这种安排更具逻辑性和可扩展性 - 但它不起作用;-)如果我有像
这样的代码MeasurementSet ms;
Measurement m = ms.SignalMeasurement;
Histogram *h = m.MassHistogram;
然后尝试用h
做一些事情,我遇到了分段错误。由于类比代码之前工作正常,我认为我没有正确处理代码中的结构。具体来说,结构是否需要以任何方式显式初始化? (Histogram
是由其他人的库提供的,只是声明Histogram *SomeHistograms[4]
足以在之前初始化它们。)
我很感激反馈。我对Python和Clojure非常熟悉,但我对C ++的有限知识并没有扩展到[看起来像]结构的护理和喂养的奥秘: - )
我将Measurement
变成了一个成熟的课程:
class Measurement {
Measurement() {
MassHistogram = new Histogram();
MomentumHistogram = new Histogram();
PositionHistogram = new Histogram();
};
~Measurement() {
delete MassHistogram;
delete MomentumHistogram;
delete PositionHistogram;
};
Histogram *MassHistogram;
Histogram *MomentumHistogram;
Histogram *PositionHistogram;
}
(我调用的通用Histogram()
构造函数工作正常。)我遇到的另一个问题是通过总是通过引用传递Measurement
来解决的。否则,析构函数将在任何接收到Measurement
的函数的末尾被调用,并且下一次尝试使用其中一个直方图会发生段错误。
谢谢大家的答案!
答案 0 :(得分:1)
当你的struct包含指针时,你必须自己初始化该变量。
例
struct foo
{
int *value;
};
foo bar;
// bar.value so far is not initialized and points to a random piece of data
bar.value = new int(0);
// bar.value now points to a int with the value 0
// remember, that you have to delete everything that you new'd, once your done with it:
delete bar.value;
struct foo
{
int *value;
};
foo bar;
// bar.value so far is not initialized and points to a random piece of data
bar.value = new int(0);
// bar.value now points to a int with the value 0
// remember, that you have to delete everything that you new'd, once your done with it:
delete bar.value;
答案 1 :(得分:1)
您知道Measurement
的定义没有为实际的Histogram
分配内存吗?在您的代码中,m.MassHistogram
是一个悬空(未初始化)指针,它不指向任何测量的Histogram
,也不指向任何能够存储Histogram
的内存。正如@Nari Rennlos刚刚发布的那样,您需要将其指向现有(或新分配的)Histogram
。
您的第三方图书馆的界面是什么样的?如果可能的话,你应该有一个Measurement
包含3 Histogram
s(而不是指向Histogram
的3个指针)。这样,当您创建Measurement
或MeasurementSet
时,将为您创建相应的Histogram
,同样适用于销毁。如果您仍需要指针,则可以使用&
运算符:
struct Measurement2 {
Histogram MassHistogram;
Histogram MomentumHistogram;
Histogram PositionHistogram;
};
MeasurementSet2 ms;
Histogram *h = &ms.SignalMeasurement.MassHistogram; //h valid as long as ms lives
另请注意,只要您不使用指针(或引用),就会按值复制和分配对象:
MeasurementSet ms; //6 uninitialized pointers to Histograms
Measurement m = ms.SignalMeasurement; //3 more pointers, values taken from first 3 above
Histogram *h = m.MassHistogram; //one more pointer, same uninitialized value
虽然指针已初始化,但此时所有10个指针都指向实际的Histogram
。
如果您有实际成员而不是指针,情况会变得更糟:
MeasurementSet2 ms; //6 Histograms
Measurement2 m = ms.SignalMeasurement; //3 more Histograms, copies of first 3 above
Histogram h = m.MassHistogram; //one more Histogram
h.firstPoint = 42;
m.MassHistogram.firstPoint = 43;
ms.SignalMeasurement.MassHistogram.firstPoint = 44;
...现在你有3个略微不同的质量信号直方图,2对相同的动量和位置信号直方图,以及三个背景直方图。
答案 2 :(得分:1)
您确定Histogram *SomeHistograms[4]
初始化了数据吗?如何填充直方图结构?
这里的问题不是结构,而是绊倒你的指针。执行此操作时:MeasurementSet ms;
它声明了MeasurementSet类型的“自动变量”。这意味着MeasurementSet的所有内存都已“分配”并准备就绪。反过来,MeasurementSet有两个类型为Measurement的变量,它们也是“已分配”和“准备就绪”。反过来,测量有3个直方图*类型的变量,它们也是“已分配”和“准备就绪”......但是等等! “直方图*”类型是“指针”。这意味着它是一个地址 - 描述实际内存位置的32位或64位(或任何位)值。就是这样。你应该指出一些东西 - 把东西放在那个位置。在它指向任何东西之前,它会在其中包含字面上的随机数据(或者数据为0,或者某些特殊的调试数据,或类似的东西) - 关键是如果你尝试用它做某事,你会得到分段错误,因为您可能会尝试读取程序不应该读取的部分数据。
在c ++中,struct几乎与一个类(在python中有类似的概念)完全相同,你通常会像这样分配一个:
m.MassHistogram = new Histogram();
......之后,直方图已准备就绪。但是,YMMV:你能自己分配吗?或者你可以从一些图书馆获得一个,也许从设备阅读等?此外,尽管你可以做我写的东西,但它并不一定“漂亮”。 c ++-ic解决方案是将分配放在构造函数中(如python中的 init )并在析构函数中删除。
答案 3 :(得分:1)
首先,要记住结构和类几乎完全相同。唯一的区别是struct默认情况下是struct public,默认情况下class成员是private。 但其余的都完全相同。
其次,仔细区分指针和对象。
如果我写
Histogram h;
将分配直方图数据的空间,并调用它的构造函数。 (构造是一个与类完全相同的方法,这里是Historgram())
如果我写
Histogram* h;
我正在声明一个32/64位的变量,它将用作指向内存的指针。它用随机值初始化。危险!
如果我写
Histogram* h = new Histogram();
将为一个Histogram的数据成员分配内存,并调用它的构造函数。内存中的地址将存储在“h”中。
如果我写
Histogram* copy = h;
我再次声明一个32/64位变量指向内存中与h
完全相同的地址如果我写
Histogram* h = new Historgram;
Histogram* copy = h;
delete h;
发生以下情况
简而言之:代码中的“n.MassHistogram”指的是内存中的随机区域。不要使用它。首先使用运算符“new”分配它,或者将其声明为“Histogram”(对象而不是指针)
欢迎来到CPP:D