简体   繁体   中英

Sorting an array of valid and invalid numbers in c++ for an embedded system

I am writing a program in C++ that will be used with Windows Embedded Compact 7. I have heard that it is best not to dynamically allocate arrays when writing embedded code. I will be keeping track of between 0 and 50 objects, so I am initially allocating 50 objects.

Object objectList[50];
int activeObjectIndex[50];
static const int INVALID_INDEX = -1;
int activeObjectCount=0;

activeObjectCount tells me how many objects I am actually using, and activeObjectIndex tells me which objects I am using. If the 0th, 7th, and 10th objects were being used I would want activeObjectIndex = [0,7,10,-1,-1,-1,...,-1]; and activeObjectCount=3; As different objects become active or inactive I would like activeObjectIndex list to remain ordered.

Currently I am just sorting the activeObjectIndex at the end of each loop that the values might change in.

First, is there a better way to keep track of objects (that may or may not be active) in an embedded system than what I am doing? If not, is there an algorithm I can use to keep the objects sorted each time I add or remove and active object? Or should I just periodically do a bubble sort or something to keep them in order?

The overhead of a std::vector is very small. The problem you can have is that dynamic resizing will allocate more memory than needed. However, as you have 50 elements, this shouldn't be a problem at all. Give it a try, and change it only if you see a strong impact.

If you cannot/do not want to remove unused objects from a std::vector, you can maybe add a boolean to your Object that indicates if it is active? This won't require more memory than using activeObjectIndex (maybe even less depending on alignment issues).

To sort the data with a boolean (not active at the end), write a function :

bool compare(const Object & a, const Object & b) {
    if(a.active && !b.active) return true;
    else return false;
}

std::sort(objectList,objectList + 50, &compare); // if you use an array
std::sort(objectList.begin(),objectList.end(), &compare); // if you use std::vector

If you want to sort using activeObjectIndex it will be more complicated. If you want to use a structure that is always ordered, use std::set. However it will require more memory (but for 50 elements, it won't be an issue).

Ideally, implement the following function :

bool operator<(const Object & a, const Object & b) {
    if(a.active && !b.active) return true;
    else return false;
}

This will allow to use directly std::sort(objectList.begin(), objectList.end()) or declare an std::set that will stay sorted.

One way to keep track of active / inactive is to have the active Objects be on a doubly linked list. When an object goes from inactive to active then add to the list, and active to inactive remove from the list. You can add these to Object

Object * next, * prev;

so this does not require memory allocation.

If no dynamic memory allocation is allowed, I would use simple c-array or std::array and an index, which points into last+1 object. Objects are always kept in sorted order.

Addition is done by inserting new object into correct position of sorted list. To find insert position lower_bound or find_if can be used. For 50 element, second probably will be faster. Removal is similar.

You should not worry about having the list sorted, as writing a method to search in a list of indices what are the ones active would be O(N) , and, in your particular case, amortized to O(1) , as your array seems to be small enough for this little extra verification.

You could maintain the index of the last element checked, until it reaches the limit:

unsigned int next(const unsigned int& last) {

    for (unsigned int i = last + 1; i < MAX_ARRAY_SIZE; i++) {
        if (activeObjectIndex[i] != -1) {
            return i;
        }
    }

    return -1;

}

However, if you really want to have a side index, you can simply double the size of the array, creating a double linked list to the elements:

activeObjectIndex[MAX_ARRAY_SIZE * 3] = {-1};
activeObjectIndex[i] = "element id";
activeObjectIndex[i + 1] = "position of the previous element";
activeObjectIndex[i + 2] = "position of the next element";

You have a hard question, where the answer requires quite a bit of knowledge about your system. Without that knowledge, no answer I can give would be complete. However, 15 years of embedded design has taught me the following:

  1. You are correct, you generally don't want to allocate objects during runtime. Preallocate all the objects, and move them to active/inactive queues.
  2. Keeping things sorted is generally hard. Perhaps you don't need to. You don't mention it, but I'll bet you really just need to keep your Objects in "used" and "free" pools, and you're using the index to quickly find/delete Objects.

I propose the following solution. Change your object to the following:

class Object {
  Object *mNext, *mPrevious;
public:
  Object() : mNext(this), mPrevious(this) { /* etc. */ }

  void insertAfterInList(Object *p2) {
    mNext->mPrev = p2;
    p2->mNext = mNext;
    mNext = p2;
    p2->mPrev = this;
  }

  void removeFromList() {
    mPrev->mNext = mNext;
    mNext->mPrev = mPrev;
    mNext = mPrev = this;
  }

  Object* getNext() {
    return mNext;
  }

  bool hasObjects() {
    return mNext != this;
  }
};

And use your Objects:

#define NUM_OBJECTS (50)
Object gObjects[NUM_OBJECTS], gFree, gUsed;

void InitObjects() {
  for(int i = 0; i < NUM_OBJECTS; ++i) {
    gFree.insertAfter(&mObjects[i]);
  }
}

Object* GetNewObject() {
  assert(mFree.hasObjects());
  Object obj = mFree->getNext();
  obj->removeFromList();
  gUsed.insertAfter(obj);
  return obj;
}

void ReleaseObject(Object *obj) {
  obj->removeFromList();
  mFree.insertAfter(obj);
}

Edited to fix a small glitch. Should work now, although not tested. :)

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