我有一个函数,给定一个路径名,查找并返回指向相关值的指针。有时该值位于静态缓存中,有时会在运行时计算和创建。
因此,有时调用者需要拥有该对象并在读取后删除它,有时则不需要。我想知道,是否有一些方法可以包装这个指针,让调用者根据需要自动释放它?
我考虑可能可以使用unique_ptr,但删除器是类型的一部分,那么如何返回相同的类型,有时实际上会删除,有时则不会呢?
std::shared_ptr
来返回其值,并为存储在map中的值创建一个空删除器的另一个智能指针。shared_ptr
,通过引用计数自动实现即可。 - DarkWandererstd::shared_ptr
,但这并不能真正描述您的所有权模型。您是否考虑过编写自己的包装器,其中包含一个 std::unique_ptr
和一个原始指针,并根据情况使用正确的指针?类似这样的东西:#include <cassert>
#include <memory>
class MyClass { };
class Wrapper {
const MyClass* cached_;
std::unique_ptr<MyClass> owned_;
public:
Wrapper() : cached_(nullptr) {}
void setCached(const MyClass* cached) {cached_ = cached;}
void setOwned(std::unique_ptr<MyClass> owned) { owned_ = std::move(owned); }
const MyClass* get() const {return cached_ ? cached_ : owned_.get();}
};
Wrapper getWrapper(int i) {
static MyClass first;
static MyClass second;
Wrapper wrapper;
if (i == 0)
wrapper.setCached(&first);
else if (i == 1)
wrapper.setCached(&second);
else
wrapper.setOwned(std::unique_ptr<MyClass>(new MyClass()));
return wrapper;
}
int main() {
for (int i = 0; i != 4; ++i) {
Wrapper wrapper = getWrapper(i);
assert(wrapper.get() != nullptr);
}
}
#include <cassert>
#include <memory>
class MyClass {};
class Wrapper {
public:
virtual ~Wrapper() = 0;
virtual const MyClass* get() const = 0;
};
Wrapper::~Wrapper() {}
class OwnerWrapper : public Wrapper {
std::unique_ptr<MyClass> owned_;
public:
OwnerWrapper(std::unique_ptr<MyClass> in) : owned_(std::move(in)) {}
virtual const MyClass* get() const { return owned_.get(); }
};
class PtrWrapper : public Wrapper {
const MyClass* ptr_;
public:
PtrWrapper(const MyClass* ptr) : ptr_(ptr) {}
virtual const MyClass* get() const { return ptr_; }
};
std::unique_ptr<Wrapper> getWrapper(int i) {
static MyClass first;
static MyClass second;
if (i == 0)
return std::unique_ptr<Wrapper>(new PtrWrapper(&first));
else if (i == 1)
return std::unique_ptr<Wrapper>(new PtrWrapper(&second));
else {
std::unique_ptr<MyClass> myclass(new MyClass());
return std::unique_ptr<Wrapper>(new OwnerWrapper(std::move(myclass)));
}
}
int main() {
for (int i = 0; i != 4; ++i) {
auto wrapper = getWrapper(i);
assert(wrapper->get() != nullptr);
}
}
std::unique_ptr
。虽然删除器 类型 是 unique_ptr
类型的一部分,但不同的 unique_ptr 实例可以有不同的删除器实例:template <class T>
class delete_if_not_cached {
bool cached;
public:
delete_if_not_cached(bool c = false) : cached(c) {}
void operator()(T *obj) { if (!cached) delete obj; }
}
如果您将函数返回为std::unique_ptr<T, delete_if_not_cached<T>>
,则可以将指针返回到缓存中,创建该指针的方法如下:
return std::unique_ptr<T, delete_if_not_cached<T>>(raw_pointer, delete_if_not_cached<T>(true));
return std::unique_ptr<T, delete_if_not_cached<T>>(new T(...))
一个潜在的陷阱是,如果您从缓存中删除东西,则可能会留下您先前返回的悬空unique_ptr
。如果这是一个问题,那么在缓存中使用shared_ptr
来返回和使用可能更有意义。
shared_ptr
可以搞定这个问题吧?如果值在缓存中存在,那么调用者将得到指向该值的共享指针,当超出范围时不会删除任何内容;如果没有,则表示调用方实际上具有新创建值的所有权,并且当共享指针超出范围时删除它。 - JBL