简体   繁体   中英

Is it a good idea to resize a dynamic array in C++ on a Microcontroller

I am building a model railroad crossing gate signal and am working on the micro controller code to make it function. I have run into an issue that has me questioning my methodology.

I am reading RFID tags (every car has one inside it), once the train triggers entry into the crossing gate zone, and putting the tag numbers into an array. The problem is that array will most likely always need to be re-sized as not every train has the same number of cars, and therefore the same number of RFID tags. I need to capture the last cars tag, as I need to monitor for that tag from the exit zone RFID reader so I know when to close the gates and shut the flashers off. Additionally, I could just count the cars as a new tag is discovered and the just match the count in the exit zone, thereby not needing the array.

Is there a more efficient way to do this besides and array? I am a C# guy so not all that familiar with how to handle in C++, with pointers and all that comes with that.

Another thought was to abandon the array and just replace a tagID variable with each tag read, thinking the last cars tag will be in the variable all the time, and match the entry and exit car count, that might be the simplest solution.

Thoughts on best approach?

In a real-world railway crossing this ultimately can affect peoples' safety. Although this is just a model, it may be a good exercise to get you thinking about the types of things you might encounter in the real world (since that's just a scaled-up version with bigger consequences).

I would recommend:

  • Make the code as simple as possible;
  • Provide internal verification measures to ensure assumptions match reality;
  • Have defined recovery procedures to handle when the above verifications fail;
  • Write unit tests to verify all edge-cases and out-of-mode operation (if you have an obsessive nature).

It is not recommended to use dynamic memory in a microcontroller environment unless you really know what you're doing. Running out of memory and crashing due to unintended fragmentation is a very real problem.

One simple approach is to record the first tag, the last tag, and the number of tags. That way you can do some sanity check on the start and exit carriages and ensure the same number of carriages exited as entered. If not, enter some alarm recovery state where you log the issue and perhaps use some timeout or other detection to determine it's safe to raise the arm.

Another approach would be to make a static array that's enough to store tags for more carriages than can physically fit between the two detectors, and use it as a ring buffer. That way you can validate every carriage as it leaves the crossing.

If you really feel the need to use dynamic memory, go ahead. But consider that if such a system could fail due to runaway allocation, then any static array solution might also fail in that scenario. And you may want to rethink your approach.

To avoid pointers and manually memory allocation you can use the class

std::vector

Vectors are sequence containers representing arrays that can change in size.

You can learn more about it here .

Well, the crossing gate zone should have a finite number of cars that can be accepted at a time. Doesn't it?

What you can do, is to implement some kind of a fixed sized queue based on a std::array<tagId,MAX_SLOTS> , and keep the actually available incoming slot index.

I would do some thing like this:

template<class T, size_t max>
class ResizeableArray{
    T array[max];
    size_t end;
  public:
    void addLast(T value){
      array[end] = value;
      end++;  //Maybe check before you do this
    }
    size_t size(){
      return end;
    }
    T operator[](size_t index){
      return array[index];  //Maybe do a check here?
    }
    void RemoveLast(){
      end--;
      array[end].~T();  //Destroy the object
    }
};

And then later you can use like this:

ResizeableArray<TrainCar,32> cars;  //Max size of 32
cars.addLast(TrainCar());
cars.addLast(TrainCar());
cars.addLast(TrainCar());
cars.addLast(TrainCar());
if (cars[1].someMethod())
  doSomthing();

The real bonus is that using this method there is no dynamic memory initialization, which I would definitely suggest if you are on a micro. The other nice thing is it acts (somewhat) like a built in list holder. If you wanted more functionality you could add it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM