Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

segfaults in C++ when using std::shared_ptr

In the code bellow, when using std::shared_ptr I get a segmentation fault. However, when using normal pointers, the same problem doesn’t occur.

In summary, I want to define a ConstrainedVariable object that will get updated according to some curve whenever the value of a reference variable is updated. The way I’ve found for implementing this involves using smart pointers, since they’ll get automatically removed from the vectors holding them whenever they’re no longer referenced (for example, when a variable is no longer used)

#include <vector>
#include <functional>
#include <memory>
#include <iostream>
#include <cmath>

using Action = std::function<void()>;
using ActionPtr = std::shared_ptr<Action>;
using ActionWeakPtr = std::weak_ptr<Action>;
using VectAct = std::vector<ActionWeakPtr>;
inline void execute(ActionPtr t){(*t)();}
inline ActionPtr action(Action t) {return std::make_shared<Action>(t);}

template<class T>
class Variable {
  protected:
    T ival; // internal value
    std::vector<ActionWeakPtr> actions;

  public:
    Variable() = default;

    inline void link(ActionPtr t) {actions.push_back(t);}

    void set(T newval) {
      if(ival == newval) return;
      static_set(newval);
      force_update();
    }

    T val() {return ival;}

  private:

    void static_set(T newval){
      ival = newval;
    }

    void force_update(){
      for(auto it = actions.begin(); it != actions.end(); /* Nothing */){
        auto action = it->lock();
        if(action){execute(action); it++;}
        else {it = actions.erase(it);}
      }
    }

};

template<class T>
using VariablePtr = std::shared_ptr<Variable<T>>;

template<class T>
inline VariablePtr<T> var() {return std::make_shared<Variable<T>>();};

template<class I, class O>
using Curve = std::function<O(I)>;

template<class I, class O>
class ConstrainedVariable : private Variable<O> {
  ActionPtr constraint;
  std::weak_ptr<Variable<I>> _refVar;
  Curve<I, O> _refCurve = [](I t){return std::sin(t);};

  public:
    void applyConstraint() {
      if(auto sharedVar = _refVar.lock()){
        this->set(_refCurve(sharedVar->val()));
      }
    }

    O val() {return this->ival;}

    ConstrainedVariable(VariablePtr<I> refVar, Curve<I, O> refCurve) :
      Variable<O>(), _refVar(refVar), _refCurve(refCurve) {
      constraint = action([this](){this->applyConstraint();});

      if(auto v = _refVar.lock()){
        v->link(constraint);
      }

      execute(constraint);
    }
};

template<class I, class O>
std::shared_ptr<ConstrainedVariable<I, O>> ctrVar(VariablePtr<I> refVar, Curve<I, O> refCurve){
  return std::make_shared<ConstrainedVariable<I, O>>(ConstrainedVariable<I, O>(refVar, refCurve));
};

int main(){
  auto v  = var<float>();

  //auto _c = ConstrainedVariable<float, float>(v, [](float t){return std::sin(t);});

  //auto* c = &_c;                                                        // WORKS
  auto c  = ctrVar<float, float>(v, [](float t){return std::sin(t);});  // DOESNT WORK

  std::cout << v->val() << std::endl;
  std::cout << c->val() << std::endl;

  v->set(1);

  std::cout << v->val() << std::endl;
  std::cout << c->val() << std::endl;

}

I haven’t been able to minimally reproduce the issue nor do I understand why this is happening. Any help is appreciated.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

The issue is in ctrVar. You construct a temporary ConstrainedVariable in the parameters to make_shared, which is then copied into the pointee.

Somewhere in your mess of pointers, there is a dangling pointer after the copy.

The fix is to pass the constructor parameters to make_shared

template<class I, class O>
std::shared_ptr<ConstrainedVariable<I, O>> ctrVar(VariablePtr<I> refVar, Curve<I, O> refCurve){
  return std::make_shared<ConstrainedVariable<I, O>>(refVar, refCurve);
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading