有没有一种惯用的方法可以返回一个指针,该指针可以选择拥有其值
Is there an idiomatic way to return a pointer that optionally owns its value
我有一个函数,它给出了一个路径名,进行查找并返回一个指向相关值的指针。有时值存在于静态缓存中,有时它会在运行中进行计算和创建。
因此,有时调用者拥有所有权,并需要在读取对象后删除该对象,有时则不然。我想知道,有没有什么东西可以包装这个指针,以便调用方在必要时自动释放它?
我在想我可能可以使用unique_ptr,但它不是类型的deleter部分,所以我怎么能返回有时确实删除,有时实际上不删除的同一类型呢。
因此,实际上,一个解决方案可能会为函数内部创建的值返回一个普通的std::shared_ptr
,而另一个方案则为映射中的值返回了一个空的deleter。
此解决方案的实时示例
您可以看到,这两个用例都不需要调用代码执行任何操作,而且是完全透明的。
您可以将std::unique_ptr
与一个知道是否释放的deleter一起使用。虽然deleter类型是unique_ptr
类型的一部分,但不同的unique_ptr实例可以有不同的deleter实例:
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; }
}
并且您的函数返回一个CCD_ 4。如果您将一个指针返回到缓存中,则将该指针创建为:
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
返回和缓存本身可能更有意义。
您可以使用std::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);
}
}
- C++为什么我的指针选择排序中存在分段错误?
- C++ 将派生类的成员函数指针作为参数传递时选择了错误的模板专用化
- 使用指针选择长无符号变量中的数字
- 选择排序指针问题
- 我想将指向 const 对象的指针放入包含非 const 指针的容器中.我有什么选择
- C++/pimpl:原始指针还是unique_ptr?什么是更好的选择?
- 我是否应该使用功能指针在构造函数中选择实现
- 为什么在指针上对成员访问/元素选择有不同的运算符
- 如何获取指向编译器选择的重载函数的函数指针
- 关于智能指针中取消引用和成员选择运算符的定义
- C++:二维指针数组排序:选择排序不适用于某些实例
- 使用指针进行选择排序
- C++ 使用指针进行选择排序功能
- 如何让编译器在指针上选择模板的静态数组版本
- 自定义UI元素使用的智能指针选择
- 如果加法表达式的第一个操作数可转换为指针和整数,则选择哪个转换
- 是否存在通过引用选择元素和通过指针操作选择元素都有效的情况
- 智能指针如何在delete和delete[]之间进行选择
- 函数指针-不能更改函数签名,我有什么选择
- 在std::容器中选择存储值还是存储指针时的注意事项