如您所知,由于包含该类的shared_pointer尚未存在,因此无法使用对象构造函数中的std :: enable_shared_from_this和shared_from_this()对。但是,我真的很想要这个功能。我尝试过自己的系统,似乎工作正常。
namespace kp
{
template <class T>
void construct_deleter(T *t)
{
if(!t->_construct_pself)
{
t->~T();
}
free(t);
}
template <class T, typename... Params>
std::shared_ptr<T> make_shared(Params&&... args)
{
std::shared_ptr<T> rtn;
T *t = (T *)calloc(1, sizeof(T));
t->_construct_pself = &rtn;
rtn.reset(t, construct_deleter<T>);
t = new(t) T(std::forward<Params>(args)...);
t->_construct_pself = NULL;
t->_construct_self = rtn;
return rtn;
}
template <class T>
class enable_shared_from_this
{
public:
std::shared_ptr<T> *_construct_pself;
std::weak_ptr<T> _construct_self;
std::shared_ptr<T> shared_from_this()
{
if(_construct_pself)
{
return *_construct_pself;
}
else
{
return _construct_self.lock();
}
}
};
}
有人能发现这种逻辑中的任何缺陷吗?在构造函数调用之前,我基本上使用placement new来指定类中的shared_ptr指针。
目前我可以这样使用它:
std::shared_ptr<Employee> emp = kp::make_shared<Employee>("Karsten", 30);
并在Employee构造函数中:
Employee::Employee(std::string name, int age)
{
Dept::addEmployee(shared_from_this());
}
在我将其提交给相对较大的代码库之前,我非常感谢您提出的一些想法或反馈。
谢谢!
答案 0 :(得分:2)
我知道已经有一段时间了,但这可能对遇到同样问题的人很有用:如果您尝试从继承enable_shared_from_this
的类中继承,则会出现主要问题。
特别是这一行:
t->_construct_pself = &rtn;
如果您说:
class Object : public kp::enable_shared_from_this<Object> {
};
class Component : public Object {
};
然后,编译器将无法将std::shared_ptr<Component>*
强制转换为std::shared_ptr<Object>*
,因为即使Component
继承了Object
,这些类型也不相关。
我看到的最简单的解决方案是像这样将_construct_pself
变成void*
:
template <class T>
class enable_shared_from_this
{
public:
void* _construct_pself{ nullptr };
std::weak_ptr<T> _construct_self;
std::shared_ptr<T> shared_from_this() const
{
if (_construct_pself)
{
return *static_cast<std::shared_ptr<T>*>(_construct_pself);
}
else
{
return _construct_self.lock();
}
}
};
然后做
t->_construct_pself = static_cast<void*>(&rtn);
它不是很性感,可能会引起其他问题,但似乎很有效...
[EDIT]有一个更好,更多的“ C ++”替代方案,很抱歉没有立即考虑它,只需执行即可:
t->_construct_pself = reinterpret_cast<decltype(t->_construct_pself)>(&rtn);
[EDIT2]使shared_from_this
保持不变,因为它不会更改类中的任何内容
[EDIT3]发现了另一个问题:如果您通过make_shared
使用复制构造函数,并且在operator=
之前的构造函数中使用shared_from_this
,则shared_from_this
将返回复制的对象,而不是对象的副本。我看到的唯一解决方案是为enable_shared_from_this
定义空的复制构造函数和赋值运算符,并在每次需要时从继承类中显式调用复制构造函数……或者确保您永远不要在{{1 }}放在复制构造函数中。
答案 1 :(得分:1)
我认为在构造函数中使用shared_from_this()存在语义问题。 问题是当抛出异常时没有有效对象,但您已经设置了一个共享指针。 e.g:
Employee::Employee(std::string name, int age)
{
Dept::addEmployee(shared_from_this());
if (...) throw std::runtime_error("...");
}
现在Dept
将有一个指向此对象的指针,该指针未成功创建。