将unique_ptr与gsl_vector一起使用

Using unique_ptr with gsl_vector

本文关键字:一起 vector unique ptr gsl      更新时间:2023-10-16

我最喜欢的unique_ptr的一个方面是它提供的自动内存管理。我想将unique_ptr与GSL向量之类的东西一起使用。

但是,gsl_vector有自己的释放内存的机制(gsl_vector_free)。有没有办法强制唯一指针使用 GSL 的矢量释放方法?Valgrind(正确)报告在创建以下unique_ptr<gsl_vector>时不匹配地使用了malloc/delete:

#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("%fn", 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("%fn", 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;
}

此外,每次我想访问矢量元素时都必须调用get()似乎相当乏味。有没有办法解决这个问题?

您可以通过

std::unique_ptr提供自定义删除器来做到这一点。像这样的事情可能会做:

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

拥有make_unique_gsl_vector和自定义删除器:

#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;
}

为了避免.get()调用和其他与将gsl_vector包装在unique_ptr中相关的样板,您可以创建一个小型 RAII 包装器。

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);
    }
};
}

这不仅避免了样板,而且还允许您轻松扩展功能,例如,添加一个采用std::initializer_list<double>的构造函数,以便您可以在单个表达式中构造和初始化向量。

现场示例