首页 > 解决方案 > 如何从返回原始指针的函数中使用智能指针

问题描述

我有一个需要使用的 C++ 库,它使用 build() 函数通过原始指针返回带有 new 的对象。我想在使用智能指针的同时使用这个对象,但到目前为止,我只找到了使用 smart_ptr.reset(build()) 的解决方案,它有效但有点难看。有没有更好的方法来做到这一点,还是我必须使用手动内存管理?

对于更多上下文,库中的函数会调用return new,我相信您需要在该指针上调用 delete。

如何将现有对象的地址分配给智能指针?这是我之前称之为“丑陋”的答案,也是我问是否有更好的方法的原因。

标签: c++smart-pointers

解决方案


这取决于。考虑这个例子:

struct example {
    ~example() { std::cout << "bye\n"; }
};

example* some_lib_function_A(){
    return new example;
}

该库返回一个指向动态分配对象的原始指针。这不好,为了避免处理原始的拥有指针,您可以包装some_lib_function_A到一个函数中,该函数返回一个管理对象的智能指针。

但是,库也可能会沿着这条线做一些事情(只是为了论证。它应该返回一个引用):

example* some_lib_function_B() {
    static example ex;
    return &ex;
} 

在这种情况下,您不能delete在不遇到问题的情况下返回指针。

完整的例子

#include <memory>
#include <iostream>
struct example {
    ~example() { std::cout << "bye\n"; }
};

example* some_lib_function_A(){
    return new example;
}

example* some_lib_function_B() {
    static example ex;
    return &ex;
} 

template <typename F>
std::unique_ptr<example> wrap(F f){
    std::unique_ptr<example> res;
    res.reset(f());
    return res;
}

int main() {
    wrap(some_lib_function_A);
    wrap(some_lib_function_B); // free(): invalid pointer
}

中的第一行符合main您的预期,但第二行会导致未定义的行为。这就是链接答案说按照以下方式编写函数不好的原因:

 std::unique_ptr<example> wrap_bad(example& ex) {
    std::unique_ptr<example> res;
    res.reset(&ex);
    return res;
 }

因为您无法知道example传递给函数的是否是动态分配的。该函数对它的作用撒谎,因为获取引用的函数在处理其参数的生命周期方面没有任何业务。它可以正确使用,但错误使用的可能性很大。

您必须阅读库文档并找出库希望您使用指针做什么。有时您必须调用一些库函数clean_up(ex)来进行适当的清理,在这种情况下,您可以将库清理函数包装在自定义删除器中。


推荐阅读