Pull to refresh

Comments 12

Вывод: При использовании статических переменных в статических библиотеках нужно следить за тем, чтобы исполняемые модули не линковались статически друг в друга.
Ещё лучше не использовать статических переменных. Они зло.
А синглтоны запретить!
Именно. Нужен один экземпляр — создавайте один экземпляр. Лениво отслеживать? Поручите DI-контейнеру.
Чтобы статья была как из песочницы, вначале лучше написать о том, что при сборке exe файла, доступ к статической переменной из методов класса будет происходить по двум разным адресам(для каждой статической линковки свой адрес), а итератор инициализируется адресом первой переменной и таким остается после вызова конструктора копирования. Для временных, экспериментальных нужд и итератор можно сделать static, чтобы первая схема линковки работала. Каждой паре по твари.
Для временных, экспериментальных нужд и итератор можно сделать static, чтобы первая схема линковки работала.

Но, согласитесь, в реальном коде Вы так специально делать не будете. А это пример из боевого кода, который привел к ошибке, которую я целый день ловил!
А тут как такого синглтона нет, получается другая концепция, т.е. одному объекту по смыслу соответствует несколько участков памяти
Посмотрел еще раз боевой код.
Здесь концепция такая: каждый объект класса является записью в некотором общем списке. Поэтому список статический, а итератор нет. Итератор является приватным членом класса. По сути этот класс представляет собой кэш. Там еще есть подсчет ссылок, поэтому две одинаковые записи списка не будут помещены в него дважды, плюс еще несколько дополнений, но я их убрал для упрощения.
Прошу прощения если я выбрал не самые понятные имена классов и методов. Хотел показать лишь саму ошибку.
Забыл еще, дописать пункт 3: вызов копирующего конструктора происходит на стороне dll, можно проверить, взять адрес static списка в debug.
Напишите подробнее пожалуйста, а то непонятно в каком случае это происходит.
*3. .exe: Вызывается конструктор копирования для объекта класса ListAndIter. У временного объекта итератор стал не валидным. У нового объекта итератор указывает на список из DLL.dll, хотя сам объект создается на стороне exe-модуля.


Вот здесь на стороне dll, а не exe происходит вызов копируещего конструктора
> Как видно из кода, есть специальная функция foo, которая служит для обхода RVO, чтобы вызывался конструктор копирования.

Каким образом foo() убивает RVO? Или это только специфика MSVC? К сожалению сейчас нет доступа к windows-машине, а в том же gcc (можно попробовать например тут coliru.stacked-crooked.com/ ), никакого убивания RVO функцией foo нет :(

P.S. Вот такой код убивания вроде как более универсальный?

ListAndIter GetStaticObj( /* require evil */ bool condition = false )
{
if( condition ) {
ListAndIter obj;
return obj;
}
else {
ListAndIter obj;
return obj;
}
}
Sign up to leave a comment.

Articles