Массив изменяется при извлечении элемента - PullRequest
0 голосов
/ 17 декабря 2018

Редактировать: добавлены конструкторы и добавить функцию

Рассмотрим следующие три блока:

//ONE
template<typename T>
class List1 {
private:
    uint32_t capacity;
    uint32_t used;
    T* data;
    void checkGrow() {
            if (used < capacity)
                    return;
            T* old = data;
            capacity*=2;
            data = (T*)new char[sizeof(T) * capacity];
            memcpy(data, old, sizeof(T)*used);
            delete (void*)old;
    }
public:
    List1() : capacity(1), used(0), data((T*)new char [sizeof(T)]) {}
    List1(uint32_t initialSize) :
            capacity(initialSize), used(0), data((T*)new char[sizeof(T)]) {}

    List1(const List1& orig) :
            capacity(orig.capacity), used(orig.used), data((T*)new char[used * sizeof(T)]) {
            memcpy(data, orig.data, used * sizeof(T));
    }
    uint32_t serializeSize() const { return sizeof(used) + used*sizeof(T); }
    char* read(char* p) {
            used = *(uint32_t*)p;
            p += sizeof(uint32_t);
            data = (T*)new char[used*sizeof(T)];
            memcpy(p, data, used * sizeof(T));
            return p + used*sizeof(T);
    }
    char* write(char* p) {
            *(uint32_t*)p = used;
            p += sizeof(uint32_t);
            memcpy(p, data, used * sizeof(T));
            return p + used * sizeof(T);
    }

    ~List1() { delete [] data; }

    void add(const T& v) {
            checkGrow();
      data[used++] = v;        
    }
    uint32_t getUsed() const{
            return used;
    }
    uint32_t getCapacity() const{
            return capacity;
    }

    //const T& operator [](int i) const { return data[i]; }
    //T& operator [](int i) { return data[i]; }
    T getData (int i) const{
            return data[i];
    }
    uint32_t size() const { return used * sizeof(T); }
};

//TWO
List1<uint32_t> temp=in.readList<uint32_t>(); // <List1<uint32_t>>();
//BREAKPOINT HERE
for(uint i=0;i<15;i++){
    //cout<<temp[i]<<endl;
    cout<<temp.getData(i)<<endl;
}

//THREE
template<typename T>
T _read() {
    T temp = *(T*)p;
    p += sizeof(T);
    availRead -= sizeof(T);
    return temp;
}

template<typename T>
T read(){
    //cout << (uint64_t)p << endl;
    checkAvailableRead(sizeof(T));
    return _read<T>();
}
template<typename T>

List1<T> readList(){
    uint32_t len = read<uint32_t>();
    List1<T> temp(len);
    for (uint i = 0 ; i < len; i++){
        T val =read<T>();
        temp.add(val);
        //HERE: For some reason code does not work without this print statement
        //cout<<temp.getData(i)<<endl;
        }
    return temp;
}

В основном проблема заключается в том, что значение данных изменяется после возврата из getData, как показано ниже.

gdb) p/u *temp.data@15  
$1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
(gdb) p/u *temp.data@15  
$2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
(gdb) p/u *data@15  
$3 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
[New Thread 8444.0xad8]
(gdb) p/u *data@15  
$4 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
[New Thread 8444.0x214c]
(gdb) p/u *temp.data@15  
$5 = {0, 1, 2, 3, 4, 5, 83, 0, 2150008464, 1, 3742232646, 0, 168272, 6, 0}

По какой-то причине добавление оператора print в readList решает проблему, но это не является разумным решением.Я пробовал несколько различных вариантов кода, но ни один из них не работал.

Я не уверен, в чем проблема или как даже начать отладку, поскольку проблема возникает между оператором return и следующей итерациейцикла (там нечего вступать).

Любой совет будет принят с благодарностью.

1 Ответ

0 голосов
/ 17 декабря 2018
List1(const List1& orig) :
        capacity(orig.capacity), used(orig.used), data((T*)new char[used * sizeof(T)]) {
        memcpy(data, orig.data, used * sizeof(T));
}

Чтобы List1 работал правильно, никогда не должно быть List1, чье capacity больше, чем фактический выделенный размер.Однако это создает новый List1, который нарушает этот инвариант, если orig имеет capacity больше, чем used.

Вы, вероятно, имели в виду capacity(orig.used).

Та же проблемаздесь:

List1(uint32_t initialSize) :
        capacity(initialSize), used(0), data((T*)new char[sizeof(T)]) {}

Если вы установите capacity в initialSize, вы не сможете выделить место только для 1 T.

Это также не работает delete (void*)old;.Что вы выделяете с помощью new[], вы должны освободить с помощью delete[].

Обратите внимание, что List1 может использоваться только для хранения типов POD (простых старых данных), которые не имеют конструкторов или деструкторов.Если вы пытаетесь использовать List1 для удержания чего-то более сложного, ваш дизайн далеко не уместен.

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