如何解决通过受保护的构造函数和静态成员函数强制std :: shared_ptr使用以创建实例和std :: make_shared
我有一些只能通过std::shared_ptr
使用的类。这些类的实例不能设计为通过在堆栈上分配它们或通过new
由原始指针直接使用。我目前通过使构造函数protected
并具有一个static
成员函数来实际执行此操作,该成员函数实际上会进行对象实例化并将shared_ptr
返回给对象:
class Example {
protected:
Example() { }
public:
static std:shared_ptr<Example> create() { return std::shared_ptr<Example>(new Example()); }
};
我意识到这不是防弹的方法,因为您仍然可以在get()
上致电shared_ptr
,但这似乎可以作为支持人员使用的一种指示。
但是,我不能使用std::make_shared()
,因为构造函数是protected
,并且我知道make_shared()
有内存分配/性能优势。
上面的做法是不好的做法,还是有没有使用make_shared()
而不构造构造函数public
的方法?
解决方法
有一个古老的技巧可以将有限的权限授予另一个函数来创建对象;您传递令牌。
struct Example_shared_only {
private:
// permission token. explicit constructor ensures
// you have to name the type before you can create one,// and only Example_shared_only members and friends can
// name it:
struct permission_token_t {
explicit permission_token_t(int) {}
};
public:
// public ctor that requires special permission:
Example_shared_only( permission_token_t ) {}
// delete special member functions:
Example_shared_only()=delete;
Example_shared_only(Example_shared_only const&)=delete;
Example_shared_only(Example_shared_only &&)=delete;
Example_shared_only& operator=(Example_shared_only const&)=delete;
Example_shared_only& operator=(Example_shared_only &&)=delete;
// factory function:
static std::shared_ptr<Example_shared_only>
make_shared() {
return std::make_shared<Example_shared_only>( permission_token_t(0) );
}
};
现在Example_shared_only::make_shared()
返回一个由shared_ptr
创建的make_shared
,其他人无能为力。
如果您可以使用C ++的更多现代方言,我们可以做得更好:
template<class F>
struct magic_factory {
F f;
operator std::invoke_result_t<F const&>() const { return f(); }
};
struct Example2 {
static std::shared_ptr<Example2> make() {
return std::make_shared<Example2>( magic_factory{ []{ return Example2{}; } } );
}
private:
Example2() = default;
};
这需要c++17才能保证清除。
magic_factory
可以强制转换为工厂函数产生的任何内容,并且可以保证简化地就地构建该对象。它在其他情况下具有更出色的用途,但是在这里,您可以导出构造函数以使其共享。
传递给magic_factory
的lambda是Example2
的隐式朋友,这使它可以访问私有ctor。有保证的省略意味着具有签名()->T
的函数可以被调用以创建T
“就地”而没有任何逻辑副本。
make_shared<T>
尝试使用参数构造其T
。 C ++在发生这种情况时会检查operator T
;我们的magic_factory
有一个这样的operator T
。因此就使用了。
它的作用类似
::new( (void*)ptr_to_storage ) Example2( magic_factory{ lambda_code } )
(如果您不熟悉,这称为“新放置”-它表示“请在Example2
指向的位置上构建ptr_to_storage
对象)。
保证清除的本质基本上是将lambda_code
的创建地址(也称为Example2
)传递到ptr_to_storage
,并在此处构造对象。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。