1

operator< オーバーロードの実装が、長い値の配列を囲むラッパー クラスに対して適切に機能しません。

std::map 内の Key にこのラッパー クラスを使用しているときに、異なる長さの配列を混在させると at/find 関数の呼び出しが機能しません。

const oid oid1[] = { 1,3,6,1,4,1,42570,1,3,1 };
oid_wrapper wrapper1(oid1, 10);
const oid oid2[] = { 1,3,6,1,4,1,42570,1,3,1,9,1 };
oid_wrapper wrapper1(oid2, 12);

最初に wrapper1 を追加してから wrapper2 をマップに追加すると、常に at/find で wrapper1 が検出されますが、wrapper2 の場合は at で out_of_range 例外がスローされ、find で iterator.end 例外がスローされます。
最初に wrapper2 を追加してから wrapper1 をマップに追加すると、常に at/find で wrapper2 が検出されますが、wrapper1 の場合は、at で out_of_range 例外がスローされ、find で iterator.end 例外がスローされます。

タイプ oid は Net-SNMP からのもので、実際には unsigned long int です。
では、私の実装に何が欠けているか、または完全に間違っているのでしょうか?

#include <ostream>
#include <sstream>
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>

class oid_wrapper {
public:
    oid_wrapper(const oid* _oid_value, int _oid_length) : oid_value(0), oid_length  (_oid_length) {
        oid_value = snmp_duplicate_objid(_oid_value, oid_length);
    }

    const oid* get_oid() const { return oid_value; }
    const int& get_length() const { return oid_length; }

    /**
     * copy operator overloader
     */
    oid_wrapper& operator=(const oid_wrapper& wrapper) {
        oid_value = snmp_duplicate_objid(wrapper.get_oid(), wrapper.get_length());
        oid_length = wrapper.get_length();

        return *this;
    }

    /**
     * equal operator overloader
     */
    bool operator==(const oid_wrapper& rhs) const {
        const oid* rhs_oid = rhs.get_oid();
        const int rhs_length = rhs.get_length();

        if (netsnmp_oid_equals(oid_value, oid_length, rhs_oid, rhs_length) == 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * less-than operator overloader
     */
    bool operator<(const oid_wrapper& rhs) const {
        const oid* rhs_oid = rhs.get_oid();
        const int rhs_length = rhs.get_length();

        if (oid_length < rhs_length) { return true; }

        for (int i = 0; i < oid_length; i++) {
            if (oid_value[i] < rhs_oid[i]) { return true; }
        }

        return false;
    }

    const long getLastNumberInOid() const { return oid_value[oid_length - 1]; }

    bool operator!=(const oid_wrapper& rhs) { return !operator==(rhs); }
    bool operator>(const oid_wrapper& rhs) { return !operator<(rhs); }
    bool operator<=(const oid_wrapper& rhs) { return !operator>(rhs); }
    bool operator>=(const oid_wrapper& rhs) { return !operator<(rhs); }

private:
    const oid* oid_value;
    int oid_length;
};

これは、機能するかどうかを確認するために設計した私のテストクラスです。

#include <iostream>
#include <ostream>
#include <string>
#include <map>
#include <stdexcept>

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>

#include "oid_wrapper.h"

using namespace std;

int main(int argc, char **argv) {

    cout << "Testing first set of OID" << endl;
    const oid oid1[] = { 1,3,6,1,4,1,40850,1,3 };
    const oid_wrapper parent1 (oid1, 9);
    const oid_wrapper parent1_child1 (parent1, 40);
    const oid_wrapper parent1_child2 (parent1, 41);
    const oid_wrapper parent1_child3 (parent1, 42);
    const oid_wrapper parent1_child4 (parent1, 43);

    map<oid_wrapper, string> test;
    test.insert(make_pair(parent1_child1, "parent1_child1"));
    test.insert(make_pair(parent1_child2, "parent1_child2"));
    test.insert(make_pair(parent1_child3, "parent1_child3"));
    test.insert(make_pair(parent1_child4, "parent1_child4"));
    if (test.size() != 4) { cout << "FAIL" << endl; }
    cout << "Number of OID in list: " << test.size() << endl;

    const oid_wrapper parent11 (oid1, 9);
    const oid_wrapper parent1_child11 (parent11, 40);
    try {
        string teststring = test.at(parent1_child11);
        cout << "Success" << endl;
    } catch (out_of_range& e) {
        cout << "Failure" << endl;
    }

    const oid_wrapper parent1_child12 (parent11, 41);
    try {
        string teststring = test.at(parent1_child12);
        cout << "Success" << endl;
    } catch (out_of_range& e) {
        cout << "Failure" << endl;
    }

    const oid_wrapper parent1_child13 (parent11, 42);
    try {
        string teststring = test.at(parent1_child13);
        cout << "Success" << endl;
    } catch (out_of_range& e) {
        cout << "Failure" << endl;
    }

    const oid_wrapper parent1_child14 (parent11, 43);
    try {
        string teststring = test.at(parent1_child14);
        cout << "Success" << endl;
    } catch (out_of_range& e) {
        cout << "Failure" << endl;
    }

    cout << "Testing second set of OID" << endl;
    const oid oid2[] = { 1,3,6,1,4,1,40850,2,1,9,1 };
    const oid_wrapper parent2 (oid2, 11);
    const oid_wrapper parent2_child1 (parent2, 1);
    const oid_wrapper parent2_child2 (parent2, 2);
    const oid_wrapper parent2_child3 (parent2, 3);
    const oid_wrapper parent2_child4 (parent2, 4);

    test.insert(make_pair(parent2_child1, "parent2_child1"));
    test.insert(make_pair(parent2_child2, "parent2_child2"));
    test.insert(make_pair(parent2_child3, "parent2_child3"));
    test.insert(make_pair(parent2_child4, "parent2_child4"));
    if (test.size() != 8) { cout << "FAIL" << endl; }
    cout << "Number of OID in list: " << test.size() << endl;

    const oid_wrapper parent21 (oid2, 11);
    const oid_wrapper parent1_child21 (parent21, 1);
    try {
        string teststring = test.at(parent1_child21);
        cout << "Success" << endl;
    } catch (out_of_range& e) {
        cout << "Failure" << endl;
    }

    const oid_wrapper parent1_child22 (parent21, 2);
    try {
        string teststring = test.at(parent1_child22);
        cout << "Success" << endl;
    } catch (out_of_range& e) {
        cout << "Failure" << endl;
    }

    const oid_wrapper parent1_child23 (parent21, 3);
    try {
        string teststring = test.at(parent1_child23);
        cout << "Success" << endl;
    } catch (out_of_range& e) {
        cout << "Failure" << endl;
    }

    const oid_wrapper parent1_child24 (parent21, 4);
    try {
        string teststring = test.at(parent1_child24);
        cout << "Success" << endl;
    } catch (out_of_range& e) {
        cout << "Failure" << endl;
    }

    //#################################################

    //Adding 100 OIDs
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2,1,9,1 };
        const oid_wrapper wrapper(newoid, 11, i);
        test.insert(make_pair(wrapper, "wrapper"));
    }

    //Query for the 100 added OIDs
    int run1 = 0;
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2,1,9,1 };
        const oid_wrapper wrapper(newoid, 11, i);

        try {
            string teststring = test.at(wrapper);
            run1++;
        } catch (out_of_range& e) {
            //FAIL
        }
    }
    if (run1 == 100) { cout << "Run 1 Success" << endl; }
    else { cout << "Run 1: " << run1 << endl; }

    //#################################################

    //Adding 100 OIDs
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,1,3 };
        const oid_wrapper wrapper(newoid, 9, i);
        test.insert(make_pair(wrapper, "wrapper"));
    }

    //Query for the 100 added OIDs
    int run2 = 0;
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,1,3 };
        const oid_wrapper wrapper(newoid, 9, i);

        try {
            string teststring = test.at(wrapper);
            run2++;
        } catch (out_of_range& e) {
            //FAIL
        }
    }
    if (run2 == 100) { cout << "Run 2 Success" << endl; }
    else { cout << "Run 2: " << run2 << endl; }

    //#################################################

    //Adding 100 OIDs
    for (int i = 0; i < 10; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2 };
        const oid_wrapper wrapper(newoid, 8, i);
        test.insert(make_pair(wrapper, "wrapper"));
    }

    //Query for the 100 added OIDs
    int run3 = 0;
    for (int i = 0; i < 10; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2 };
        const oid_wrapper wrapper(newoid, 8, i);

        try {
            string teststring = test.at(wrapper);
            run3++;
        } catch (out_of_range& e) {
            //FAIL
        }
    }
    if (run3 == 10) { cout << "Run 3 Success" << endl; }
    else { cout << "Run 3: " << run3 << endl; }

    //#################################################

    //Adding 100 OIDs
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2,2,5,1 };
        const oid_wrapper wrapper(newoid, 11, i);
        test.insert(make_pair(wrapper, "wrapper"));
    }

    //Query for the 100 added OIDs
    int run4 = 0;
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2,2,5,1 };
        const oid_wrapper wrapper(newoid, 11, i);

        try {
            string teststring = test.at(wrapper);
            run4++;
        } catch (out_of_range& e) {
            //FAIL
        }
    }
    if (run4 == 100) { cout << "Run 4 Success" << endl; }
    else { cout << "Run 4: " << run4 << endl; }

    //#################################################

    //Adding 100 OIDs
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2,3,5,2 };
        const oid_wrapper wrapper(newoid, 11, i);
        test.insert(make_pair(wrapper, "wrapper"));
    }

    //Query for the 100 added OIDs
    int run5 = 0;
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2,3,5,2 };
        const oid_wrapper wrapper(newoid, 11, i);

        try {
            string teststring = test.at(wrapper);
            run5++;
        } catch (out_of_range& e) {
            //FAIL
        }
    }
    if (run5 == 100) { cout << "Run 5 Success" << endl; }
    else { cout << "Run 5: " << run5 << endl; }

    //#################################################

    //Adding 100 OIDs
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2,2,5,2 };
        const oid_wrapper wrapper(newoid, 10, i);
        test.insert(make_pair(wrapper, "wrapper"));
    }

    //Query for the 100 added OIDs
    int run6 = 0;
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2,2,5,2 };
        const oid_wrapper wrapper(newoid, 10, i);

        try {
            string teststring = test.at(wrapper);
            run6++;
        } catch (out_of_range& e) {
            //FAIL
        }
    }
    if (run6 == 100) { cout << "Run 6 Success" << endl; }
    else { cout << "Run 6: " << run6 << endl; }

    //#################################################

    //Adding 100 OIDs
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2,5,2,3,5 };
        const oid_wrapper wrapper(newoid, 12, i);
        test.insert(make_pair(wrapper, "wrapper"));
    }

    //Query for the 100 added OIDs
    int run7 = 0;
    for (int i = 0; i < 100; i++) {
        const oid newoid[] = { 1,3,6,1,4,1,40850,2,5,2,3,5 };
        const oid_wrapper wrapper(newoid, 12, i);

        try {
            string teststring = test.at(wrapper);
            run7++;
        } catch (out_of_range& e) {
            //FAIL
        }
    }
    if (run7 == 100) { cout << "Run 7 Success" << endl; }
    else { cout << "Run 7: " << run7 << endl; }
}
4

2 に答える 2

1

問題は、あなたoperator<が反対称ではない可能性があります。次のコードを想像してください。

const oid oid1[] = {5};
oid_wrapper wrapper1(oid1, 1);

const oid oid2[] = {1, 4};
oid_wrapper wrapper2(oid2, 2);

bool b1 = wrapper1 < wrapper2;
bool b2 = wrapper2 < wrapper1;

b1true、 のwrapper1長さが の長さより短いためですwrapper2

b2trueの最初の oidwrapper2が のそれよりも小さいため、もwrapper1です。

operator<完全な注文であることを確認する必要があります。falseの場合は返されますoid_length > rhs_length

operator>また、 asを実装することはできませ! <ん。これは、等しい値には当てはまらないためです。オペレーターにとって最善の策は、実装operator==operator<て残りを (疑似コード) として表現することです。

operator!=(a, b)  {! (a == b)}
operator<=(a, b)  {a < b || a == b}
operator>(a, b)   {! (a < b)}
operator>=(a, b)  {! (a < b)}
于 2012-11-19T11:22:53.183 に答える
0

独自の比較を実装する代わりに、net-snmp 関数 snmp_oid_compare を使用しました。これで問題は解決しました。

#ifndef OID_WRAPPER_H_
#define OID_WRAPPER_H_

#include <stdio.h>
#include <stdlib.h>

#include <ostream>
#include <sstream>

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>

class oid_wrapper {
    friend std::ostream& operator<<(std::ostream& output, const oid_wrapper& wrapper);
public:
    oid_wrapper(const oid* _oid_value, unsigned long _oid_length) : oid_value(0), oid_length(_oid_length) {
        oid_value = snmp_duplicate_objid(_oid_value, oid_length);

    }

    const oid* get_oid() const { return oid_value; }
    const unsigned long& get_length() const { return oid_length; }

    int compare(const oid_wrapper& rhs) const {
        return snmp_oid_compare(oid_value, oid_length, rhs.oid_value, rhs.oid_length);
    }

    void print(std::ostream &out) const {
        for(unsigned long i = 0; i < oid_length; i++) {
            if (i != 0) { out << "."; }
            out << oid_value[i];
        }
    }

    /**
     * copy operator overload
     */
    oid_wrapper& operator=(const oid_wrapper& wrapper) {
        if (oid_value != 0) { free(oid_value); }

        oid_value = snmp_duplicate_objid(wrapper.oid_value, wrapper.oid_length);
        oid_length = wrapper.oid_length;

        return *this;
    }

    /**
     * assignment operator overload
     */
    oid operator[](unsigned long i) {
        return (i < oid_length) ? oid_value[i] : oid();
    }

    bool operator==(const oid_wrapper& rhs) const { return compare(rhs)==0; }
    bool operator!=(const oid_wrapper& rhs) const { return compare(rhs)!=0; }
    bool operator<(const oid_wrapper& rhs) const { return compare(rhs)<0; }
    bool operator>(const oid_wrapper& rhs) const { return compare(rhs)>0; }
    bool operator<=(const oid_wrapper& rhs) const { return compare(rhs)<=0; }
    bool operator>=(const oid_wrapper& rhs) const { return compare(rhs)>=0; }

private:
    oid* oid_value;
    unsigned long oid_length;
};

/**
 * output operator overloader
 */
inline std::ostream& operator<<(std::ostream& output, const oid_wrapper& wrapper) {
    wrapper.print(output);
    return output;
}

#endif /* OID_WRAPPER_H_ */



関数 snmp_oid_compare のコード。これは、long の配列を比較する必要があるあらゆる実装に使用できます。

    int snmp_oid_compare(const oid * in_name1, size_t len1, 
                     const oid * in_name2, size_t len2)
    {
        register int len;
        register const oid *name1 = in_name1;
        register const oid *name2 = in_name2;

        /*
         * len = minimum of len1 and len2
         */
        if (len1 < len2) { len = len1; }
        else { len = len2; }

        /*
         * find first non-matching OID
         */
        while (len-- > 0) {
            /*
             * these must be done in seperate comparisons, since
             * subtracting them and using that result has problems with
             * subids > 2^31.
             */
            if (*(name1) != *(name2)) {
                if (*(name1) < *(name2)) { return -1; }
                return 1;
            }
            name1++;
            name2++;
        }

        /*
         * both OIDs equal up to length of shorter OID
         */
        if (len1 < len2) return -1;
        if (len2 < len1) return 1;

        return 0;
    }        
于 2012-11-21T09:41:13.647 に答える