mercredi 31 mars 2021

getting a segfault when I try to deep copy `unique_ptr`s

Why can't I return a unique_ptr from a clone function? I thought I could do this.

I have a base class for different mathematical functions called transform. I have a container of pointers to this type because I am using polymorphism. For example, all these derived classes have a different implementation of log_jacobian that is useful for statistical algorithms.

I am using unique_ptrs to this transform class, and so I have made a (pure virtual) clone function that makes new unique_ptr pointing to a deep copy of the same mathematical transform object. This new object is of the same type that derives from transform<float_t>, but it's a separate because you can't have two unique_ptrs pointing to the same thing.

template<typename float_t>
class transform{
...
virtual std::unique_ptr<transform<float_t>> clone() const = 0;
...
};

My transform_container class holds a few of these at a time. After all, most statistical models have more than one parameter.

template<typename float_t, size_t numelem>
class transform_container{
private:

    using array_ptrs = std::array<std::unique_ptr<transform<float_t>>, numelem>;
    array_ptrs m_ts;
    unsigned m_add_idx;
...
    auto get_transforms() const -> array_ptrs;
};

I'm not sure why the deep copy function get_transforms isn't working, though. It is used to make copies, and to access individual transformations from the container. I get a segfault when I run some tests. If I run it in gdb, it explicitly tells me the line with a comment after it is bad.

template<typename float_t, size_t numelem>
auto transform_container<float_t,numelem>::get_transforms() const -> array_ptrs
{
    array_ptrs deep_cpy;
    for(size_t i = 0; i < numelem; ++i){
        deep_cpy[i] = m_ts[i]->clone(); // this line
    }
    return deep_cpy;
}

I've also tried std::moveing it into deep_cpy[i] and using unique_ptr::reset, but to no avail.

Edit:

here are some other relevant methods: a method that adds transforms to transform_container, and the factory method for the individual transform:

template<typename float_t>
std::unique_ptr<transform<float_t> > transform<float_t>::create(trans_type tt)
{
    if(tt == trans_type::TT_null){
        
        return std::unique_ptr<transform<float_t> >(new null_trans<float_t> );
    
    }else if(tt == trans_type::TT_twice_fisher){
        
        return std::unique_ptr<transform<float_t> >(new twice_fisher_trans<float_t> );
    
    }else if(tt == trans_type::TT_logit){
        
        return std::unique_ptr<transform<float_t> >(new logit_trans<float_t> );
    
    }else if(tt == trans_type::TT_log){

        return std::unique_ptr<transform<float_t> >(new log_trans<float_t> );
    
    }else{

        throw std::invalid_argument("that transform type was not accounted for");
    
    }
}

template<typename float_t, size_t numelem>
void transform_container<float_t, numelem>::add_transform(trans_type tt)
{
    m_ts[m_add_idx] = transform<float_t>::create(tt);
    m_add_idx++;
}

Aucun commentaire:

Enregistrer un commentaire