Using unique_ptr with gsl_vector

五迷三道 提交于 2019-12-12 18:35:27

问题


One of my favorite aspects of unique_ptr is the automatic memory management it provides. I would like to use unique_ptr with something like a GSL vector.

However, gsl_vector has its own mechanism for freeing memory (gsl_vector_free). Is there a way to force the unique pointer to use GSL's vector freeing method? Valgrind (correctly) reports a mismatched use of malloc/delete when creating a unique_ptr<gsl_vector> below:

#include <memory>
#include <gsl/gsl_vector.h>

void mem_gsl() {
  gsl_vector *vec;
  vec = gsl_vector_calloc(2);
  gsl_vector_set(vec, 0, 2.0);
  printf("%f\n", gsl_vector_get(vec, 0));
  gsl_vector_free(vec);  // Without this, there is a memory leak.
}

void mem_unique_ptr() {
  std::unique_ptr<gsl_vector> vec;
  vec.reset(gsl_vector_calloc(2));
  // Using .get() each time I want to use the gsl_vector seems like overhead.
  gsl_vector_set(vec.get(), 0, 2.0);
  printf("%f\n", gsl_vector_get(vec.get(), 0));
  // Valgrind correctly reports a mismatched use of delete and free.
}

int main(int argc, char *argv[]) {
  mem_gsl();
  mem_unique_ptr();
  return 0;
}

Additionally, having to call get() each time I want to access a vector element seems rather tedious. Is there a way around this?


回答1:


You can do it by providing std::unique_ptr with a custom deleter. Something like this would probably do:

auto del = [](gsl_vector* p) { gsl_vector_free(p); };
std::unique_ptr<gsl_vector, decltype(del)> vec(gsl_vector_calloc(2), del);



回答2:


Having a make_unique_gsl_vector amd a custom deleter:

#include <memory>

// Fake gsl
typedef int gsl_vector;
gsl_vector* gsl_vector_calloc(std::size_t) { return 0; }
void gsl_vector_free(gsl_vector*) {}

// Deleter
struct gsl_vector_deleter {
    void operator () (gsl_vector* p) {
        gsl_vector_free(p);
    }
};

// Unique Pointer
typedef std::unique_ptr<gsl_vector, gsl_vector_deleter> unique_gsl_vector;
unique_gsl_vector make_unique_gsl_vector() {
    return unique_gsl_vector(gsl_vector_calloc(2));
}

int main() {
    make_unique_gsl_vector();
    return 0;
}



回答3:


To avoid the .get() calls and other boilerplate associated with wrapping a gsl_vector in a unique_ptr, you could create a small RAII wrapper.

namespace gsl {

class vector
{
    std::unique_ptr<gsl_vector, decltype(&gsl_vector_free)> v_;
public:

    explicit vector(std::size_t num)
    : v_(gsl_vector_calloc(num), gsl_vector_free)
    {}

    double operator[](std::size_t idx) const
    {
        return gsl_vector_get(v_.get(), idx);
    }

    void set(std::size_t idx, double value)
    {
        gsl_vector_set(v_.get(), idx, value);
    }
};

}

This not only avoids boilerplate, but also allows you to easily extend functionality, say for instance, adding a constructor that takes a std::initializer_list<double> so you can construct and initialize the vector in a single expression.

Live example



来源:https://stackoverflow.com/questions/20889117/using-unique-ptr-with-gsl-vector

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!