Search code examples
c++pointersstluniqueshared

Smart Pointers - Segmentation Fault at Program Termination


I've been making a state-thingy to replace some much poorer code I've been using. I wanted to be as modern as possible, so I'm using STL wherever appropriate. I decided to use unique_ptr and shared_ptr, which I've never done before. As a result, I've hit a very scary run-time error: munmap_chunk(): invalid pointer: 0x00007fff7b3f08e0 All I know is the error has to do with free() and malloc(), but I haven't used any of that in my code, so I assume it's coming from inside STL. To make things even stranger, if I put a std::cout << "Hello World!\n"; at the beginning of main, I just get a Segmentation fault My code is relatively small so-far:

state.hpp:

#pragma once
#include "state_manager.hpp"

class state{
 using manager_ptr = std::shared_ptr<state_manager>;
protected:
 manager_ptr man;
public:
 const manager_ptr manager() const;
 void manager(manager_ptr&& parent_manager);
};

state.cpp:

#include "state.hpp"

const state::manager_ptr state::manager() const{
 return man;
}

void state::manager(manager_ptr&& parent_manager){
 man = parent_manager;
}

state_manager.hpp:

#pragma once
#include <stack>
#include <memory>

class state;

class state_manager{
 using element = std::unique_ptr<state>;
 using container =  std::stack<element>;
protected:
 container states;
public:
 void push(element&& to_push);
 void pop();
 void change(element&& change_to);
};

state_manager.cpp:

#include "state_manager.hpp"
#include "state.hpp"

void state_manager::push(element&& to_push){
 states.push(std::forward<element>(to_push));
 states.top()->manager(std::shared_ptr<state_manager>(this));
}

void state_manager::pop(){
 states.pop();
}

void state_manager::change(element&& change_to){
 states.pop();
 push(std::forward<element>(change_to));
}

main.cpp:

#include "state_manager.hpp"
#include "state.hpp"
#include <iostream>

int main(int argc, const char* argv[]){
 state_manager test;
 test.push(std::make_unique<state>());
 test.change(std::make_unique<state>());
 test.pop();
}

Solution

  • In this line of code:

    states.top()->manager(std::shared_ptr<state_manager>(this));
    

    You are constructing a shared_ptr that points to this. That means that when the shared_ptr's reference count drops to zero, it will delete this. This is bad, as the class is not the owner of this. In your case, the this pointer isn't even allocated by new, so the shared_ptr will not be able to delete it.

    You could use just a normal C++ pointer for man in your state_manager class, as it currently doesn't need ownership of the pointer.

    Alternatively you need some other way to get a shared_ptr or weak_ptr that points to this, e.g. by passing it in to push (which would be weird).