Обновление статического члена в вызове функции вызывает сбой - PullRequest
2 голосов
/ 17 января 2012

У меня есть класс polymer с static int count. Когда я создаю новый polymer для добавления в массив указателей, я использую count, чтобы найти правильное местоположение в массиве, а затем я обновляю count в конструкторе. При компиляции в Windows это работало. Однако при компиляции в Linux (Ubuntu) происходит сбой, если я не удаляю обновление count из конструктора.

РАБОТАЕТ в Windows и Ubuntu:

polymerPointer[polymer::count] = new polymer();
polymer::count++;

КОГДА конструктор не обновляет статическую переменную (см. Ниже)

polymer::polymer(){
    //sets up lots of variables but doesn't update the static member
};

Аварии в Ubuntu (работает в Windows):

polymerPointer[polymer::count] = new polymer();

КОГДА конструктор обновляет статическую переменную (см. Ниже)

polymer::polymer(){
    //sets up lots of variables and then updates the static member
    count++;
};

Я могу переписать код, но мне понравилось не вспоминать об обновлении переменной отдельно, поэтому я поместил обновление в конструктор. Любые идеи о том, что идет не так?

Ответы [ 5 ]

2 голосов
/ 17 января 2012

Вы столкнулись с неопределенным поведением.

Следующее:

polymerPointer[polymer::count] = new polymer();
polymer::count++;

не эквивалентно

polymerPointer[polymer::count] = new polymer();

, где polymer() увеличивается polymer::count.

Неопределенное поведение проистекает из того факта, что вы изменяете значение и используете это значение в том же выражении:

§1.9 p15 Если сторонавлияние на скалярный объект не секвенировано относительно другого побочного эффекта на тот же скалярный объект или вычисления значения с использованием значения того же скалярного объекта, поведение не определено.

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

Это плохой дизайнпоместить приращение количества в другое место, чем то, где вы фактически вставляете в массив.Вам нужно написать статическую функцию-член, которая добавляет элементы в массив и обновляет счетчик, а затем использует его вместо того, чтобы вручную создавать объект и вручную помещать его в массив, ожидая, что счетчик будет обновляться автоматически.

class polymer {
    static void create_new_polymer() {
        polymerPointer[polymer::count] = new polymer();
        count++;
    }
};

Еще лучше было бы просто использовать vector и управлять им своим собственным счетом:

polymerPointer.push_back(new polymer());
1 голос
/ 17 января 2012

Это может быть связано с неинициализированной переменной.Попробуйте пройти по коду в отладчике или просто распечатать значение count.

. Вы также можете проверить, что polymerPointer указывает на выделенную память (сколько памяти вы выделили для хранилища и есть ли онодостаточно для всех значений count?).

1 голос
/ 17 января 2012

Ваша проблема в том, что стандарт не гарантирует, в каком порядке выполняется ваш оператор, поэтому polymerPointer[polymer::count] = new polymer(); может оценить polymer::count до или после выполнения new polymer();.

Если вы изменили polymer::count внутри polymers конструктора и polymer::count оценивается после new polymer(), вы явно пропускаете индексы, что, вероятно, приводит к вашим сбоям.

Но действительно ли у вас есть какая-то неотложная причина использовать здесь массив, похожий на c-style вместо использования std::vector (для которого не нужна дополнительная переменная count)? Кроме того, если у вас есть выбор, вам не следует использовать ручное управление памятью, поэтому используйте std::unique_ptr или std::shared_ptr, если у вас есть доступ к C ++ 11, std::tr1::shared_ptr или boost::shared_ptr в противном случае. Если вы используете boost boost::ptr_vector, это также опция

1 голос
/ 17 января 2012

Компилятор может по закону оценить polymerPointer[polymer::count] до new polymer(); или наоборот, как он пожелает. Это означает, что вы не можете полагаться на polymer::count, чтобы быть исходным значением. Вы должны использовать что-то более детерминированное, например std::vector<std::unique_ptr<Polymer>>?

0 голосов
/ 17 января 2012

Самым простым решением было бы разделить это назначение на две части, следовательно, введя последовательность :

polymer*& insert_point = polymerPointer[polymer::count];
insert_point = new polymer();

Аргументация объясняется в других ответах.

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