2017-09-26 152 views
0

因此发生了一些奇怪的事情。我绑定了一个回调函数(我在代码的其他部分已经做了好几次),但由于某种原因,这次它导致析构函数被调用,并且在它上面存在段错误...std :: bind在析构函数上导致了分段错误

这里是我与所有多余的东西代码剥离

GUILogicComponent.h

class GUILogicComponent : public LogicComponent { 
private: 
    std::function<void()> callback; 
    EventListenerComponent* eventListener; 
    SpriteComponent& sprite; 
public: 
    GUILogicComponent(EventListenerComponent* el, SpriteComponent& s, std::function<void()> cb); 
    ~GUILogicComponent(); 
    void clicked(int x, int y); 
}; 

GUILogicComponent.cpp

GUILogicComponent::GUILogicComponent(EventListenerComponent* el, SpriteComponent& s, std::function<void()> cb) : eventListener(el), sprite(s), callback(cb) { 
    eventListener->addMouseFunction(std::bind(&GUILogicComponent::clicked, *this, std::placeholders::_1, std::placeholders::_2), SDL_BUTTON_LEFT); 
    // TODO: Binding causes seg fault 
} 

GUILogicComponent::~GUILogicComponent() { 
    delete eventListener; 
} 

void GUILogicComponent::clicked(int x, int y) { 
    if (sprite.pointInSprite(x, y)) 
     callback(); 
} 

的GDB错误

Thread 3 received signal SIGSEGV, Segmentation fault. 
0x0000000100004e73 in Thor_Lucas_Development::GUILogicComponent::~GUILogicComponent (
    this=<error reading variable: Cannot access memory at address 0x7fff5f3ffff8>) 
    at Components/GUILogicComponent.cpp:11 
11 GUILogicComponent::~GUILogicComponent() { 

不知道发生了什么事。奇怪的是,删除其他构造函数参数(删除精灵和回调,并注释掉所有相关的代码),而不是我的这个错误。

Thread 3 received signal SIGSEGV, Segmentation fault. 
0x00000001000027b8 in std::__1::__tree<std::__1::__value_type<Thor_Lucas_Development::Mousecode, std::__1::function<void (int, int)> >, std::__1::__map_value_compare<Thor_Lucas_Development::Mousecode, std::__1::__value_type<Thor_Lucas_Development::Mousecode, std::__1::function<void (int, int)> >, std::__1::less<Thor_Lucas_Development::Mousecode>, true>, std::__1::allocator<std::__1::__value_type<Thor_Lucas_Development::Mousecode, std::__1::function<void (int, int)> > > >::destroy(std::__1::__tree_node<std::__1::__value_type<Thor_Lucas_Development::Mousecode, std::__1::function<void (int, int)> >, void*>*) (this=0x10070c768, __nd=0x1007365d0) 
    at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__tree:1377 
1377  if (__nd != nullptr) 

这里的Mousecode定义在我Util.h

/** 
* Used to store a mouse state for mapping to functions. 
*/ 
struct Mousecode { 
    Uint8 button; /**< The mouse button pressed (i.e\. SDL_BUTTON_LEFT). */ 
    Uint8 state; /**< The state of the mouse button (i.e\. SDL_RELEASED). */ 
}; 

inline bool const operator==(const Mousecode& l, const Mousecode& r) { 
    return (l.button == r.button) && (l.state == r.state); 
} 

inline bool const operator<(const Mousecode& l, const Mousecode& r) { 
    return (l.button < r.button) || ((l.button == r.button) && (l.state < r.state)); 
} 

这里是EventListenerComponent做

void EventListenerComponent::addMouseFunction(std::function<void(int, int)> func, Uint8 button, Uint8 state) { 
    Mousecode code = {button, state}; 
    mouseFunctionMap[code] = func; 
} 

而且mouseFunctionMap

std::map<Mousecode, std::function<void(int, int)>> mouseFunctionMap; 

任何帮助将不胜感激d ...谢谢!

+1

当bind被添加到C++ 11时,'bind'大多已经过时;在这里我什么都看不到,用拉姆达不能做得更清楚。考虑这样做;更少的魔力,更明确的是什么是副本和什么是参考。 – Yakk

+0

尝试'std :: bind(&GUILogicComponent :: clicked,this,...)',在'this'之前没有星号。我怀疑你正在复制'GUILogicComponent'并将其传递给'bind'。 –

+0

谢谢! @IgorTandetnik –

回答

1

您正在创建一个临时副本路过这里*this

eventListener->addMouseFunction(std::bind(&GUILogicComponent::clicked, *this, std::placeholders::_1, std::placeholders::_2), SDL_BUTTON_LEFT); 

这是该行后立刻销毁。

您没有显示其他复制/移动构造函数和操作符,我怀疑你没有编码它们。请参阅What is The Rule of Three?
这会导致相同指针的双重删除。

您应该使用std:::unique_ptr,因为您的组件似乎拥有它的所有权。

+0

哇,我觉得非常愚蠢!谢谢,我只是删除了*以不解除引用。附注:我应该考虑对我的实体使用shared_ptr吗?实体拥有所有权,但有时单个组件需要彼此了解。我一直在做的方式是将指针*传递给要在析构函数中删除的实体,但将引用传递给其他组件。 –

+0

@ThorCorreia如果您的组件共享该所有权,则是,请改用shared_ptr。 –