如何避免双重删除?

时间:2014-09-22 15:23:20

标签: c++ shared-ptr delete-operator

有人可以在这里进行双重删除,以及如何避免这种崩溃?崩溃仅在程序退出时发生。

#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()。我需要flyweight存储中的shared_ptrs。

3 个答案:

答案 0 :(得分: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 ++运行时破坏static Sleeping prototype;时调用析构函数。

程序崩溃是因为shared_ptr的析构函数试图删除未在堆上分配的指针。

怎么做
如果prototypes仅包含代码中的静态对象,则根本不需要使用shared_ptr,因为这些对象将在程序退出时自动删除。将prototypes声明为

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

Demo

如果prototypes可以同时包含静态和动态对象,则表示它可以包含动态对象,因此也可以将Sleeping::prototype设为shared_ptr

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

Demo

此外,如果您在整个代码中使用shared_ptr<State>,我建议为其创建一个typedef,这样您就可以轻松地将其更改为State*或其他任何您想要的指针类型。

答案 1 :(得分:1)

使用shared_ptr时,应立即从原始指针创建它,然后忽略该点前的原始指针。如果使用相同的原始指针创建 second shared_ptr,则会获得第二次删除。您也不应该自己删除原始指针。

不幸的是,您没有显示足够的代码来确切地知道问题所在。

答案 2 :(得分:0)

程序在地图中破坏相同的State,静态变量破坏程序的结尾。

但真正的问题是你的状态是一个静态变量,你把它的地址传递给shared_ptr。在它的生命周期结束时,shared_ptr不仅会调用对象的析构函数,还会尝试释放它所获得的指针。但是您的对象在静态存储中并且释放静态存储区域中的对象是无效的。

带走1:不要将未使用new创建的对象传递给shared_ptr

带走2:使用make_shared创建共享指针。