2016-11-09 3 views
0

У меня есть статической переменной в функции класса шаблон:статическая переменная в функции шаблонного класса перезаписаны глобальной статической переменной

template<class T> 
struct builder 
{ 
    static T* buildOrGet() 
    { 
     static T* built = nullptr; 
     if(built == nullptr) built = new T; 
     return built; 
    } 
}; 

и где-то в коде глобальной переменной с конструктором.

static SomeClass global_var; 

Сначала я не знал, что случилось, но переменная built была повреждена в определенной точке программы без причины. Затем я добавил 4-байтовую точку останова данных в visual studio на &built, чтобы узнать, кто раздавил ее память после built = new T;, и фактически она находится во время динамического инициализатора C++ при инициализации членов global_var в конструкторе SomeClass. Код находится в dll, автоматически загружается exe в зависимости от него. Это как global_var память перекрытий built память, которая очень странная.

Я действительно не понимаю, почему и как это может произойти, кроме ошибки в Visual Studio 2015, вы можете мне помочь?

+0

Можете ли вы дать более подробную информацию, в частности о SomeClass? В частности, существует ли вероятность того, что в его конструкторе произойдет незаконная операция записи? – Eternal

+0

на самом деле 'SomeClass' имеет некоторые члены данных, и когда была остановлена ​​точка останова данных, я смотрел адрес своих членов для текущего экземпляра, а один из них был адресом' built' + 1, это означает, что память, занятая ' global_var' перекрывает 'встроенную 'память. И члены просто инициализированы, они не перезаписывают какую-либо память (в сборке код, в котором срабатывает точка останова, соответствует инициализации члена: что-то вроде: move rcx this mov rcx + 28h 0 <- точка прерывания данных, вызванная здесь – Juicebox

+0

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

ответ

0

Я нашел решение: На самом деле у меня есть несколько global_var с тем же именем в разных единицах трансляции моей библиотеки DLL, но они не имеют такого же типа (скажем, у другого int типа).

В этом случае (это странно для меня, потому что они являются «статическими»), компоновщик просто сохраняет один и использует одну и ту же память для всех переменных (здесь хранится int).

Это где идет неправильно ... Конструктор SomeClass еще называется для global_var я уже упоминал выше, но его память не sizeof(SomeClass), но sizeof(int) и это где переполнение происходит.

Для меня это ошибка, потому что линкер должен был заметить меня об этих одноименных переменных с разными типами и/и должен избегать вызова конструктора на переменную, которая не соответствует построенной памяти.

Решение: никогда не объявляйте две статические переменные с одним и тем же именем в разных единицах перевода, только один выживет, и вы не можете догадаться, какой из них.

+0

Когда вы объявляете статическую переменную в глобальной области видимости, то, что означает ключевое слово 'static', заключается в том, что переменная не должна быть доступна из других единиц перевода (чтобы избежать конфликтов имен) , Компилятор, не распечатывающий предупреждение, является нормальным. То, что я не получаю, - это то, что в блоке трансляции было выделено только 'sizeof (int)', в котором 'global_var' имеет тип' SomeClass' – Eternal

+0

Это то, что я нашел странным, но это так ... когда Я смотрю '& global_var' в отладчике, я скажу' 0x20', когда я его разбиваю, и я ввожу его конструктор, 'this' должен быть' 0x20' правильно? Но ** это не **, это похоже на то, что строительство происходит где-то в другом месте, а не на «global_var», которое я смотрел, и именно здесь я начал задаваться вопросом о том, какая оптимизация произошла в компоновщике ... и кажется, что он «сливается» «Инициализация одноименной переменной или что-то в этом роде. Простое изменение имени решило мою проблему. – Juicebox

Смежные вопросы