Индивидуальный контейнер работает нормально с g ++ (Rstudio), не очень хорошо с MSVS 2012

У меня есть фрагмент кода теста C ++, который отлично работает в Rstudio, который использует g ++, но приведет к ошибке во время выполнения в MSVS 2012:

template<typename T>
struct vec{
T*head, *tail;
vec()
{
head=NULL;
tail=NULL;
}
vec(int n)
{
head=(T*)malloc(sizeof(T)*n);
tail=head+n;
}
T operator [] (int i) const {return *(head+i);}
T & operator [] (int i) {return *(head+i);}
~vec(){free(head);}
};

int main(){
std::vector<int>y(3);
y[0]=1; y[1]=2; y[2]=3;
vec<int>x1(3);
x1[0]=y[0];
std::cout<<"vec of integers, [] overloading works fine \n";
std::vector<std::vector<int>::iterator>z(3);
z[0]=y.begin();
z[1]=y.begin()+1;
z[2]=y.begin()+2;
vec<std::vector<int>::iterator>x2(3);
x2[0]=z[0];
std::cout<<*x2[0]<<"\n";
std::cout<<"vec of std::vector::iterator, [] overloading g++ works fine, MSVS doesn't \n";
return 1;
}

Код показывает, что если vec содержит целые числа, MSVS и Rstudio работают нормально; если vec содержит итераторы, MSVS столкнется со следующей ошибкой:

введите описание изображения здесь

Я чувствовал, что это как-то связано с итераторами. Кто-нибудь может дать мне знать, где моя ошибка? Кстати, я включил только файл заголовка вектора в MSVS.

Спасибо!

0

Решение

Вы выделяете (неинициализированную) память, используя malloc и пытаться интерпретировать его как не-POD типы, такие как итераторы. Это обязательно потерпит неудачу — operator= поскольку объект ожидает инициализированный объект в качестве своего левого операнда, но вы задаете ему значение мусора (отсюда и сбой).

Кроме того, вы не вызываете деструкторы ваших элементов, так как вы используете простой free,

Простое решение заключается в использовании new T[n] в вашем конструкторе вместо malloc (а также delete[] в деструкторе). Это требует вашего T быть конструируемым по умолчанию; Есть способы ослабить это требование (включая размещение new и некоторые хитрости, чтобы гарантировать выравнивание).

Кстати, ваш vec Класс не реализует ни «правило трех», ни «правило пяти», ни отключает конструкцию копирования, поэтому вы получите двойное освобождение в случае, если ваш объект vec будет когда-либо скопирован.

1

Другие решения

VS имеет дополнительную проверку ошибок, запечатываемую итераторам в режиме отладки. Он нашел законную ошибку в вашем коде! Ошибка в том, что вы повторно интерпретируете неинициализированную память как инициализированные объекты:

vec(int n){head=(T*)malloc(sizeof(T)*n);tail=head+n;}
^^^^^^^^^^^^^^^^^^^^^^^

T & operator [] (int i) {return *(head+i);}
^^^^^^^^^

x2[0]=z[0];
^^^^^^

Назначение звонков operator= на объекте итератора вектора, который является действительно неинициализированной памятью, что приводит к сбою, который вы видите, когда он пытается интерпретировать часть этой памяти как допустимые данные. (Кстати, 0xCDCDCDCD — это то, чем отладчик обычно заполняет неинициализированную память, чтобы помочь быстрее обнаруживать подобные ошибки.)

Я предлагаю использовать new/delete вместо malloc. Простое выделение памяти сложно сделать правильно в C ++ (где нормальное управление памятью уже достаточно сложное).

Обратите внимание, что в общем случае malloc может не дать блоков с достаточно высоким выравниванием для всех типов объектов (хотя это будет происходить в большинстве случаев, так как очень немногие объекты выровнены по более чем 16 байтам).

2

По вопросам рекламы [email protected]