Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing and maintaining structs of structs

I’m writing C++ code to deal with a bunch of histograms that are populated from laboratory measurements. I’m running into problems when I try to organize things better, and I think my problems come from mishandling pointers and/or structs.

My original design looked something like this:

// the following are member variables
Histogram *MassHistograms[3];
Histogram *MomentumHistograms[3];
Histogram *PositionHistograms[3];

where element 0 of each array corresponded to one laboratory measurement, element 1 of each corresponded to another, etc. I could access the individual histograms via MassHistograms[0] or similar, and that worked okay. However, the organization didn't seem right to me—if I were to perform a new measurement, I’d have to add an element to each of the histogram arrays. Instead, I came up with

struct Measurement {
    Histogram *MassHistogram;
    Histogram *MomentumHistogram;
    Histogram *PositionHistogram;
};

As an added layer of complexity, I further wanted to bundle these measurements according to the processing that has been done on their data, so I made

struct MeasurementSet {
    Measurement SignalMeasurement;
    Measurement BackgroundMeasurement;
};

I think this arrangement is much more logical and extensible—but it doesn’t work ;-) If I have code like

MeasurementSet ms;
Measurement m = ms.SignalMeasurement;
Histogram *h = m.MassHistogram;

and then try to do stuff with h, I get a segmentation fault. Since the analogous code was working fine before, I assume that I’m not properly handling the structs in my code. Specifically, do structs need to be initialized explicitly in any way? (The Histograms are provided by someone else’s library, and just declaring Histogram *SomeHistograms[4] sufficed to initialize them before.)

I appreciate the feedback. I’m decently familar with Python and Clojure, but my limited knowledge of C++ doesn’t extend to [what seems like] the arcana of the care and feeding of structs :-)


What I ended up doing

I turned Measurement into a full-blown class:

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;
}

(The generic Histogram() constructor I call works fine.) The other problem I was having was solved by always passing Measurements by reference; otherwise, the destructor would be called at the end of any function that received a Measurement and the next attempt to do something with one of the histograms would segfault.

Thank you all for your answers!

like image 620
bdesham Avatar asked Feb 22 '26 10:02

bdesham


2 Answers

Are you sure that Histogram *SomeHistograms[4] initialized the data? How do you populate the Histogram structs?

The problem here is not the structs so much as the pointers that are tripping you up. When you do this: MeasurementSet ms; it declares an 'automatic variable' of type MeasurementSet. What it means is that all the memory for MeasurementSet is 'allocated' and ready to go. MeasurementSet, in turn, has two variables of type Measurement that are also 'allocated' and 'ready to go'. Measurement, in turn, has 3 variables of type Histogram * that are also 'allocated' and 'ready to go'... but wait! The type 'Histogram *' is a 'pointer'. That means it's an address - a 32 or 64 bit (or whatever bit) value that describes an actual memory location. And that's it. It's up to you to make it point to something - to put something at that location. Before it points to anything, it will have literally random data in it (or 0'd out data, or some special debug data, or something like that) - the point is that if you try to do something with it, you'll get a segmentation fault, because you will likely be attempting to read a part of data your program isn't supposed to be reading.

In c++, a struct is almost exactly the same thing as a class (which has a similar concept in python), and you typically allocate one like so:

m.MassHistogram = new Histogram();

...after that, the histogram is ready-to-go. However, YMMV: can you allocate one yourself? Or can you only get one from some library, maybe from a device reading, etc? Furthermore, although you can do what I wrote, it's not necessarily 'pretty'. A c++-ic solution would be to put the allocation in a constructor (like init in python) and delete in a destructor.

like image 131
Colin Avatar answered Feb 25 '26 01:02

Colin


When your struct contains a pointer, you have to initialize that variable yourself. Example

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;

like image 28
Nari Rennlos Avatar answered Feb 25 '26 01:02

Nari Rennlos



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!