Странность Transient Copy Constructor - PullRequest
1 голос
/ 13 февраля 2012

Этот класс определен в заголовочном файле:

class E_IndexList {
public:
    E_UIntegerList* l;
    inline void *data() { // retrieve packed data: stride depends on type (range)
        return l->data();
    }
    inline void insert(unsigned value) {
        if (value > maxval[l->range]) {
            promote();
            insert(value);
        } else {
            l->push_back(value);
        }
    }
    inline size_t size() {
        return l->size();
    }
    inline unsigned long get(int index) {
        return l->get(index);
    }
    void promote() {
        if (l->range == E_UIntegerList::e_byte) {
            E_UShortList *new_short_list = new E_UShortList(*((E_UByteList*)l));
            delete l;
            l = new_short_list;
        } else if (l->range == E_UIntegerList::e_short) {
            E_UIntList *new_int_list = new E_UIntList(*((E_UShortList*)l));
            delete l;
            l = new_int_list;
        } else ASSERT(false);
    }
    // start off with bytes by default
    E_IndexList() {
        l = new E_UByteList;
    }
    E_IndexList(E_UIntegerList::int_bits range) {
        switch(range) {
        case E_UIntegerList::e_byte:
            l = new E_UByteList;
            break;
        case E_UIntegerList::e_short:
            l = new E_UShortList;
            break;
        case E_UIntegerList::e_int:
            l = new E_UIntList;
            break;
        default:
            ASSERT(false);
            break;
        }
    }
    E_IndexList(const E_IndexList& cpy) { // copy ctor
        switch(cpy.l->range) {
        case E_UIntegerList::e_byte:
            l = new E_UByteList(((E_UByteList*)cpy.l)->list);
            break;
        case E_UIntegerList::e_short:
            l = new E_UShortList(((E_UShortList*)cpy.l)->list);
            break;
        case E_UIntegerList::e_int:
            l = new E_UIntList(((E_UShortList*)cpy.l)->list);
            break;
        default:
            ASSERT(false);
            break;
        }
    }
    ~E_IndexList() {
        delete l;
    }
};

Вот еще несколько классов, которые он использует:

static const unsigned long maxval[] = {0xff,0xffff,0xffffffff};
class E_UIntegerList {
public:
    enum int_bits {e_byte = 0, e_short = 1, e_int = 2};
    virtual ~E_UIntegerList() {}
    int_bits range;
    virtual void push_back(int i) = 0;
    virtual void *data() = 0;
    virtual size_t size() = 0;
    virtual unsigned long get(int index) = 0;
};
struct E_UByteList:public E_UIntegerList {
    std::vector<unsigned char> list;
    E_UByteList() {
        range = e_byte;
    }
    E_UByteList(const std::vector<unsigned char>& copy) {
        list = copy;
    }
    inline void push_back(int i) {
        list.push_back(i);
    }
    inline void *data() { return list.data(); }
    inline size_t size() { return list.size(); }
    inline unsigned long get(int index) { return list[index]; }
};
struct E_UShortList:public E_UIntegerList {
    std::vector<unsigned short> list;
    E_UShortList() {
        range = e_short;
    }
    E_UShortList(const std::vector<unsigned short>& copy) {
        list = copy;
    }
    E_UShortList(const E_UByteList& promotee) {
        range = e_short;
        list.assign(promotee.list.begin(),promotee.list.end()); // assignment should be compatible
    }
    inline void push_back(int i) {
        list.push_back(i);
    }
    inline void *data() { return list.data(); }
    inline size_t size() { return list.size(); }
    inline unsigned long get(int index) { return list[index]; }
};
struct E_UIntList:public E_UIntegerList {
    std::vector<unsigned int> list;
    E_UIntList() {
        range = e_int;
    }
    E_UIntList(const std::vector<unsigned int>& copy) {
        list = copy;
    }
    E_UIntList(const E_UShortList& promotee) {
        range = e_int;
        list.assign(promotee.list.begin(),promotee.list.end());
    }
    inline void push_back(int i) {
        list.push_back(i);
    }
    inline void *data() { return list.data(); }
    inline size_t size() { return list.size(); }
    inline unsigned long get(int index) { return list[index]; }
};

Теперь, когда я использую этот класс, у меня есть std::vector<E_IndexList>, который я использую в качестве контейнера списков индексов.

Странное поведение заключается в том, что когда я запускаю программу, иногда у нее не возникает проблем, а иногда она утверждает ложь.

Так что это большой красный флаг для меня, потому что происходит что-то очень подозрительное. Скорее всего, я в конечном итоге откажусь от всего E_IndexList, пока не начну работать над сетевым кодом игры, до которого еще далеко. Но я хотел бы знать, что здесь происходит.

Каждый имеющийся у меня ctor устанавливает диапазон на допустимое значение из перечисления в E_UIntegerList, так как же это утверждение может когда-нибудь сработать? И я не могу начать объяснять, почему такое поведение противоречиво. Тест, который вызывает этот код, не является многопоточным.

Ответы [ 3 ]

3 голосов
/ 13 февраля 2012

Ваш конструктор E_UByteList from-vector не устанавливает значение range.

Весь дизайн немного дрянной;Вы должны научиться использовать списки инициализатора конструктора, и я бы, вероятно, наделил базовый класс защищенным конструктором, который устанавливает значение range и который можно вызывать из инициализаторов производных конструкторов.

2 голосов
/ 13 февраля 2012

Вы не определили оператор присваивания.См. правило трех .

1 голос
/ 13 февраля 2012

Ваши конструкторы, такие как этот:

E_UByteList(const std::vector<unsigned char>& copy) {
    list = copy;
}

не инициализируют range из родительского E_UIntegerList класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...