2014-09-22 3 views
-1

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

#include <iostream> 
#include <string> 
#include <unordered_map> 
#include <memory> 
#include <conio.h> 

struct State; 

struct FlyweightStates { 
    static std::unordered_map<std::string, std::shared_ptr<State>> prototypes; 
    static void insertPrototype (const std::string& tag, State* state) { 
     prototypes.emplace(tag, std::shared_ptr<State>(state)); 
     std::cout << tag << " inserted in FlyweightStates::prototypes." << std::endl; 
    } 
}; 
std::unordered_map<std::string, std::shared_ptr<State>> FlyweightStates::prototypes; 

struct State { 
    virtual ~State() {std::cout << "State destructor called." << std::endl; _getch();} 
    State (const std::string& name) { 
     FlyweightStates::insertPrototype(name, this); 
    } 
}; 

struct Sleeping : public State { 
    static Sleeping prototype; 
    Sleeping() : State("Sleeping") {} 
}; 
Sleeping Sleeping::prototype; 

int main() {} 

Также врезается является следующее:

struct FlyweightStates { 
    static std::unordered_map<std::string, std::shared_ptr<State>> prototypes; 
    static void insertPrototype (const std::string& tag, std::shared_ptr<State> state) { 
     prototypes.emplace(tag, state); 
     std::cout << tag << " inserted in FlyweightStates::prototypes." << std::endl; 
    } 
}; 
std::unordered_map<std::string, std::shared_ptr<State>> FlyweightStates::prototypes; 

struct State { 
    virtual ~State() {std::cout << "State destructor called." << std::endl; _getch();} 
    State (const std::string& stateName) { 
     FlyweightStates::insertPrototype (stateName, std::shared_ptr<State>(this)); 
    } 
}; 

Что я могу сделать, чтобы избежать двойного удаления? Я не могу использовать shared_from_this(). Мне нужно shared_ptrs в мусорном хранилище.

+4

Это тонна кода без указания того, что не удается или где он терпит неудачу. Пожалуйста, предоставьте более подробную информацию. – nvoigt

+0

Авария возникает только при выходе из программы. – prestokeys

+1

@nvoigt Это полный пример. [Coliru] (http://coliru.stacked-crooked.com/a/ec05e67ebd3cdcf4) – Csq

ответ

1

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

К сожалению, у вас недостаточно кода, чтобы точно знать, в чем проблема.

+0

Авария возникает только при выходе из программы. Итак, есть два владельца, которые оба считают, что они владеют указателем, но как я могу избежать этого? Я не могу использовать shared_from_this(). – prestokeys

0

Программа уничтожает те же State на карте и статическую переменную конца программы.

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

Отнять 1: не пропускать объекты, не созданные с new до shared_ptr.

Отберите 2: используйте make_shared для создания общего указателя.

+0

На стеке? В самом деле? –

+0

@LightnessRacesinOrbit нет, не очень, спасибо – Csq

4

The object is destroyed and its memory deallocated when either of the following happens: the last remaining shared_ptr owning the object is destroyed, ...

Таким образом, один вызов деструктора происходит, когда shared_ptr разрушается. И еще один раз деструктор вызывается, когда C++ runtime уничтожает static Sleeping prototype;.

Программа вылетает из-за того, что деструктор shared_ptr пытается удалить указатель, который не был выделен в куче.

Что делать
Если prototypes будет содержать только статические объекты, как в вашем коде, то нет никакой необходимости использовать shared_ptr вообще, так как эти объекты будут удалены автоматически при выхода из программы.Объявить prototypes как

static std::unordered_map<std::string, State*> prototypes; 

Demo

Если prototypes может содержать как статические, так и динамические объекты, то это означает, что он может содержать только динамические объекты, так что Sleeping::prototypeshared_ptr, а также:

static std::shared_ptr<Sleeping> prototype; 
... 
std::shared_ptr<Sleeping> Sleeping::prototype(new Sleeping()); 

Demo

Кроме того, если вы используете shared_ptr<State> во всем своем коде, я бы посоветовал сделать typedef для этого, поэтому вы можете легко изменить его на State* или любой другой тип указателя, который вы хотите.

+0

Вся моя программа использует объекты State с shared_ptr, так что вы уверены, что безопасно хранить состояния прототипов в виде исходных указателей? – prestokeys

+0

@prestokeys Если объекты имеют статическую продолжительность хранения, как в вашем коде, то да, исходные указатели в порядке. –

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