惰性共享指针 - 赋值运算符
Lazy shared pointer - assignment operator
我创建了简单的惰性共享指针 class。但是,目前我只能拥有它的单个实例,而且我的设计不支持复制分配。
/// <summary>
/// Simple lazy shared pointer
/// Pointer is initialized when first needed
///
/// Create new instance with CreateLazy static method
///
/// Copy is disabled, pointer can only be moved
/// If we would copy it not initialized
/// then two instances can be created
/// - from original and from copy
/// </summary>
template <class T>
class LazySharedPtr{
public:
static LazySharedPtr<T> Create(){
std::function<std::shared_ptr<T>()> customInit = [](){
return std::make_shared<T>();
};
return LazySharedPtr(customInit);
};
template <typename ... Args>
static LazySharedPtr<T> Create(Args ... args){
return LazySharedPtr(std::forward<Args>(args) ...);
};
LazySharedPtr() :
init(nullptr),
ptr(nullptr){
};
LazySharedPtr(std::function<std::shared_ptr<T>()> customInit) :
init(customInit),
ptr(nullptr){
};
template <typename Y>
LazySharedPtr(LazySharedPtr<Y> && other) :
init(other.init),
ptr(other.ptr){
other.init = nullptr;
other.ptr = nullptr;
};
LazySharedPtr(const LazySharedPtr& other) = delete;
virtual ~LazySharedPtr() = default;
T* operator->(){
return InitAndGet().get();
}
const T* operator->() const{
return InitAndGet().get();
}
T* operator*(){
return InitAndGet().get();
}
const T* operator*() const{
return InitAndGet().get();
}
explicit operator bool() const noexcept{
return (ptr != nullptr);
}
explicit operator std::shared_ptr<T>() const{
return InitAndGet();
}
template <typename U>
friend class LazySharedPtr;
protected:
std::function<std::shared_ptr<T>()> init;
mutable std::shared_ptr<T> ptr;
template <typename ... Args>
LazySharedPtr(Args ... args) :
init([args = std::make_tuple(std::forward<Args>(args) ...)]() mutable {
return std::apply(std::make_shared<T, Args...>, std::move(args));
}),
ptr(nullptr){
};
std::shared_ptr<T>& InitAndGet() const {
if (!ptr) { ptr = init(); }
return ptr;
}
};
你有什么想法,如何改进它以支持复制分配?
目前的设计不支持这个:
class MyObject { };
LazySharedPtr<MyObject> t1 = LazySharedPtr<MyObject>::Create();
LazySharedPtr<MyObject> t2 = t1;
因为t2
初始化后,t1
不会被初始化
我曾想过将内部 shared_ptr
作为指向指针的指针并将其传递。但是,使用原始指针我必须管理引用计数并且做 std::shared_ptr<std::shared_ptr<T>>
看起来很奇怪。或者没有?
你还有别的想法吗?
这是一个草图 - 未经测试,缺少的部分应该很容易填写。我希望大意是清楚的。
template <class T>
class LazySharedPtr {
struct ControlBlock {
std::shared_ptr<T> ptr;
std::function<std::shared_ptr<T>()> factory;
std::shared_ptr<T> InitAndGet() {
// Add thread safety here.
if (!ptr) {
ptr = factory();
factory = nullptr;
}
return ptr;
}
};
std::function<std::shared_ptr<T>()> init;
// This member is not strictly necessary, it's just a cache.
// An alternative would be to call `init` every time.
std::shared_ptr<T> ptr;
public:
// For exposition, assume all `T`s are constructible from `int`
LazySharedPtr(int x) {
auto control = std::make_shared<ControlBlock>();
control->factory = [x]() { return std::make_shared<T>(x); };
init = [control]() {return control->InitAndGet(); }
}
template <typename U>
LazySharedPtr(const LazySharedPtr<U>& other)
: ptr(other.ptr) {
if (!ptr) {
auto other_init = other.init;
init = [other_init]() { return std::shared_ptr<T>(other_init()); };
}
}
std::shared_ptr<T> InitAndGet() {
if (!ptr) {
ptr = init();
init = nullptr;
}
return ptr;
}
};
基本上,一直向下键入擦除。
我创建了简单的惰性共享指针 class。但是,目前我只能拥有它的单个实例,而且我的设计不支持复制分配。
/// <summary>
/// Simple lazy shared pointer
/// Pointer is initialized when first needed
///
/// Create new instance with CreateLazy static method
///
/// Copy is disabled, pointer can only be moved
/// If we would copy it not initialized
/// then two instances can be created
/// - from original and from copy
/// </summary>
template <class T>
class LazySharedPtr{
public:
static LazySharedPtr<T> Create(){
std::function<std::shared_ptr<T>()> customInit = [](){
return std::make_shared<T>();
};
return LazySharedPtr(customInit);
};
template <typename ... Args>
static LazySharedPtr<T> Create(Args ... args){
return LazySharedPtr(std::forward<Args>(args) ...);
};
LazySharedPtr() :
init(nullptr),
ptr(nullptr){
};
LazySharedPtr(std::function<std::shared_ptr<T>()> customInit) :
init(customInit),
ptr(nullptr){
};
template <typename Y>
LazySharedPtr(LazySharedPtr<Y> && other) :
init(other.init),
ptr(other.ptr){
other.init = nullptr;
other.ptr = nullptr;
};
LazySharedPtr(const LazySharedPtr& other) = delete;
virtual ~LazySharedPtr() = default;
T* operator->(){
return InitAndGet().get();
}
const T* operator->() const{
return InitAndGet().get();
}
T* operator*(){
return InitAndGet().get();
}
const T* operator*() const{
return InitAndGet().get();
}
explicit operator bool() const noexcept{
return (ptr != nullptr);
}
explicit operator std::shared_ptr<T>() const{
return InitAndGet();
}
template <typename U>
friend class LazySharedPtr;
protected:
std::function<std::shared_ptr<T>()> init;
mutable std::shared_ptr<T> ptr;
template <typename ... Args>
LazySharedPtr(Args ... args) :
init([args = std::make_tuple(std::forward<Args>(args) ...)]() mutable {
return std::apply(std::make_shared<T, Args...>, std::move(args));
}),
ptr(nullptr){
};
std::shared_ptr<T>& InitAndGet() const {
if (!ptr) { ptr = init(); }
return ptr;
}
};
你有什么想法,如何改进它以支持复制分配?
目前的设计不支持这个:
class MyObject { };
LazySharedPtr<MyObject> t1 = LazySharedPtr<MyObject>::Create();
LazySharedPtr<MyObject> t2 = t1;
因为t2
初始化后,t1
不会被初始化
我曾想过将内部 shared_ptr
作为指向指针的指针并将其传递。但是,使用原始指针我必须管理引用计数并且做 std::shared_ptr<std::shared_ptr<T>>
看起来很奇怪。或者没有?
你还有别的想法吗?
这是一个草图 - 未经测试,缺少的部分应该很容易填写。我希望大意是清楚的。
template <class T>
class LazySharedPtr {
struct ControlBlock {
std::shared_ptr<T> ptr;
std::function<std::shared_ptr<T>()> factory;
std::shared_ptr<T> InitAndGet() {
// Add thread safety here.
if (!ptr) {
ptr = factory();
factory = nullptr;
}
return ptr;
}
};
std::function<std::shared_ptr<T>()> init;
// This member is not strictly necessary, it's just a cache.
// An alternative would be to call `init` every time.
std::shared_ptr<T> ptr;
public:
// For exposition, assume all `T`s are constructible from `int`
LazySharedPtr(int x) {
auto control = std::make_shared<ControlBlock>();
control->factory = [x]() { return std::make_shared<T>(x); };
init = [control]() {return control->InitAndGet(); }
}
template <typename U>
LazySharedPtr(const LazySharedPtr<U>& other)
: ptr(other.ptr) {
if (!ptr) {
auto other_init = other.init;
init = [other_init]() { return std::shared_ptr<T>(other_init()); };
}
}
std::shared_ptr<T> InitAndGet() {
if (!ptr) {
ptr = init();
init = nullptr;
}
return ptr;
}
};
基本上,一直向下键入擦除。