2016-03-07 2 views
2

У меня возникли проблемы с разработкой того, как написать класс полиморфного отжига. Я уверен, что я делаю что-то очень не так, и что это повторяющийся вопрос, но я долго искал и ничего не нашел.Segfault при вызове метода подкласса

Я хочу взять указатель на экземпляр абстрактного типа State (называемый pState) и использовать чистые виртуальные функции Perturb() (который случайно изменяет состояние бит) и Cost() (который оценивает стоимость функция), чтобы найти состояние, которое минимизирует функцию стоимости.

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

void Annealer::Minimise(State *pState){ 
    //Set up 
    .... 
    .... 
    State *state; 
    State *newState; 

    *state = *pState; 
    *newState = *state; 

    //Evaluate the initial cost 
    pState->Cost(); //Works just fine 
    double cost = state->Cost(); //Segfault 

    .... 
} 

Стоимость вызова на указатель подкласса перед попыткой копирования выполнена успешно. Я не включил подкласс, потому что он очень длинный и сложный.

Edit:

государство определяется следующим образом:

class State { 
public: 
    virtual void Perturb()=0; 
    virtual double Cost()=0; 
}; 
+0

Вы должны опубликовать исходный код класса State.Я бы предположил, что ошибка может быть связана с копированием объектов, а не с указателями в: – Anorflame

+2

Между определением переменной 'state' и присваиванием' * state = * pState', вы делаете 'state' фактически точкой где-то действительным? Тот же вопрос с 'NewState'. Задумывались ли вы о том, чтобы эти переменные ('state' и' newState') не указали переменные? –

+0

Как я могу сделать их точными? Я хочу избежать использования динамического распределения памяти, если это возможно. –

ответ

0

Да, вы объявляете переменную состояния как указатель, затем разыменования указателя, который имеет неизвестное значение, поэтому не указывают на действительный объект. Это плохая идея и в конечном итоге приведет к segfault или к доступу к неопределенной области памяти. Если вы не знаете подходящий подкласс состояния как при вызове метода, так и внутри него, я бы сказал, что у вас должна быть, например, функция чистого виртуального клонирования, которая создаст копию текущего состояния. Конечно, в подклассах это было бы почти одинаково. Но, как-то я считаю, что это может быть несколько уродливым, не уверен, что думают другие, я не опытный разработчик C++.
Если ваш сайт вызова, то есть функция, передающая указатель состояния, знает соответствующий подкласс, тогда вы можете рассмотреть возможность использования шаблонов, даже в сочетании с полиморфизмом.

+0

Ahh, если состояние является абстрактным классом, то вы можете только копировать указатели, как правило. –

+0

Есть ли способ получить копию '* pState' в стеке, чтобы указать? –

+0

Но мне нужно 'state' и' newState', чтобы иметь возможность указывать на разные значения, поэтому я не думаю, что указатели копирования позволят мне достичь того, что я хочу. –

2

Проблема здесь:

*state = *pState; 
*newState = *state; 

Вы пытаетесь скопировать pState в там, где переменная состояния указывает, что не было установлено. Вы должны выделить память, если вы собираетесь копировать:

virtual State* State::clone() = 0; 
State *state; 
State *newState; 
state = pState->clone(); 
newState = state->clone(); 
// do some stuff 
delete state; 
delete newState; 

или сохранить его в качестве указателя:

State *state; 
State *newState; 
state = pState; 
newState = state; 

Или гибрид из 2-х вариантов, в том случае, просто сделать копию вносить изменения и копирование в основных переменную, если справедливы и без ошибок:

virtual State* State::clone() = 0; 
virtual void State::copy(State* cpy) = 0; 
State *state; 
State *newState; 
state = pState; 
newState = state->clone(); 
... // do stuff to newState 
state->copy(newState); // copy changes to input 
delete newState; 

Edit: Из-за проблемы с полиморфизмом и скопировать конструкторы, вы можете реализовать чистый виртуальный Клон e, но это приведет к распределению без стека, и вам нужно будет удалить или использовать автоматический указатель.

Copy object - keep polymorphism

+0

Не думаю, что я могу сделать первый вариант, поскольку State содержит чистые виртуальные функции. И я думаю, что второй вариант заставит state и newState указывать на одно и то же место, тогда как я хочу, чтобы два ** разных ** указателя отображались в значениях, которые являются копиями '* pState'. –

+0

Согласен, рассмотрим следующее: http://stackoverflow.com/questions/22008053/polymorphism-with-copy-constructor Однако этот метод больше не является распределением стека, поэтому вам нужно будет запомнить локальные переменные. – LINEMAN78

0

Кроме того, обратите внимание, что конструктор копирования, что называется, является одним из класса государства. Это может вызвать проблему, если реализация Cost зависит от того, как данные фактического класса также будут скопированы в задании.

+0

Это зависит от полей подклассов, поэтому проблема там тоже. –

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