Coding std::sort on struct that needs deep copy

157 views Asked by At

I have a struct

typedef unsigned int    gsk_uint32;
typedef struct _gsk_oid {
    int                 count;
    gsk_uint32 *        elements;
} gsk_oid;
struct oidX : public gsk_oid
{
    oidX();     // Default
    oidX(int countX, gsk_uint32 first, ...);        // From list of integers
    oidX(const char* oidString);        // From dotted notation
    oidX(const gsk_oid *inOID);     // From gsk_oid
    ~oidX();        // destructor
};

I have a struct that has the above OidX as a member:

struct oidPair {
    oidX *TheOID;
    const char *Descript;
    oidPair(oidX *inputOID, const char *inputDescript); 
    ~oidPair();
};

I define an array of the above structs

oidPair testOIDs[4] = {
    oidPair(new oidX("2.23.140.1.2.3"), "Certificates issued in accordance with the CA/Browser Forum's Baseline Requirements - Individual identity asserted"),
    oidPair(new oidX("2.23.140.1.1"), "Extended Validation (EV) guidelines certificate policy"),
    oidPair(new oidX("1.3.6.1.4.1.4146.1.20"), "Organization validation certificate policy"),
    oidPair(new oidX("2.23.140.1.2.2"), "Certificates issued in accordance with the CA/Browser Forum's Baseline Requirements - Organization identity asserted") };

Yes, I could define them in sorted order but there are lot more elements than I list above and I would like to avoid traps for the unwary, so at startup I want to sort the above array. I issue std::sort(testOIDs, testOIDs+4, &Oid_less);

Here's the compare function:

int DecodeOID::Oid_cmp(const gsk_oid *left, const gsk_oid *right)
{
    int cnt = std::min(left->count, right->count);      // Shorter of the two vectors
    int ret = memcmp(left->elements, right->elements, cnt*4); // compare elements
    if ( 0 != ret ) return ret;  // if unequal we are done
    return left->count - right->count;      // else longer is considered greater
}
bool DecodeOID::Oid_less(const oidPair &left, const oidPair &right)
{
    const gsk_oid *l = left.TheOID;
    const gsk_oid *r = right.TheOID;
    int ret = Oid_cmp(l, r);
    return ret < 0;
}

The third time that sort calls Oid_less &right references an oidPair with an uninitialized OidX and it fails on a memory exception. I understand that I may need a move operator or something like that, but I don't know exactly what to code. Suggestions appreciated.

1

There are 1 answers

0
Charles On

Thank you all. Yes, adding a copy and operator=() to oidPair (based on swap) solved the problem. I was focusing on the OidX where the exception was occurring, but of course it is the oidPair's that are being sorted.

Overhead is not a major concern. The table is at this point 22 items and will probably no more than double. It starts out almost in the correct order, so the number of swaps is minimal.

    friend void swap(oidPair& first, oidPair& second) // nothrow
    {
        using std::swap;
        swap(first.TheOID, second.TheOID);
        swap(first.Descript, second.Descript);
    }
    oidPair& operator=(oidPair other) 
    {
        swap(*this, other); 
        return *this;
    }
    oidPair(const oidPair &key)      // System copy
    {
        this->TheOID = new oidX(key.TheOID);
        this->Descript = key.Descript;
    }