C++ 如果不启用来自此的共享,是否可以实现来自此的共享?
使用此中的C++ 如果不启用来自此的共享,是否可以实现来自此的共享?,c++,shared-ptr,multiple-inheritance,weak-ptr,enable-shared-from-this,C++,Shared Ptr,Multiple Inheritance,Weak Ptr,Enable Shared From This,使用此中的已启用\u共享\u时,似乎存在一些边缘情况。例如: 是否可以在不使用启用\u shared \u from \u this的情况下实现共享\u this?如果可以,是否可以使其速度更快?是的,它可以使用类型的全局哈希表 unordered_map< T*, weak_ptr<T> > Ashared\u ptr是三件事。它是一个参考计数器、一个破坏者和一个拥有的资源 当您使_共享时,它一次分配所有3个,然后在一个块中构造它们 当您从T*创建shared\u
已启用\u共享\u时,似乎存在一些边缘情况。例如:
是否可以在不使用启用\u shared \u from \u this
的情况下实现共享\u this
?如果可以,是否可以使其速度更快?是的,它可以使用类型的全局哈希表
unordered_map< T*, weak_ptr<T> >
Ashared\u ptr
是三件事。它是一个参考计数器、一个破坏者和一个拥有的资源
当您使_共享时
,它一次分配所有3个,然后在一个块中构造它们
当您从T*
创建shared\u ptr
时,您将单独创建引用计数器/销毁程序,并注意所拥有的资源是T*
shared\u from\u this
的目标是,我们基本上可以从T*
中提取shared\u ptr
(假设它存在)
如果通过创建的所有共享指针都使_共享
,这将很容易(除非您希望定义失败时的行为),因为布局很容易
但是,并非所有共享指针都是这样创建的。有时,您可以创建一个指向不是由任何std
库函数创建的对象的共享指针,因此T*
与共享指针引用计数和销毁数据无关
由于T*
或它所指向的内容(通常)中没有找到此类构造的空间,因此我们必须将其存储在外部,这意味着全局状态和线程安全开销以及其他问题。这对不需要共享此
的人来说是一个负担,并且与需要它的人(互斥、查找等)的当前状态相比,这是一个性能打击
当前设计将弱\u ptr
存储在启用\u共享\u from\u this
中。只要调用make_shared
或shared_ptr
ctor,就会初始化此弱_ptr
。现在我们可以从T*
创建shared\u ptr
,因为我们通过继承enable\u shared\u from\u this
在类中为它“腾出了空间”
#include <memory>
#include <iostream>
#include <unordered_map>
#include <cassert>
using namespace std;
template<class T>
struct MySharedFromThis {
static unordered_map<T*, weak_ptr<T> > map;
static std::shared_ptr<T> Find(T* p) {
auto iter = map.find(p);
if(iter == map.end())
return nullptr;
auto shared = iter->second.lock();
if(shared == nullptr)
throw bad_weak_ptr();
return shared;
}
};
这同样是非常低的成本,并且可以很好地处理简单的案例。最后,我们的开销比aT
的基线成本低一个弱的ptr
当您有两个不同的共享的\u this
时,它们的弱\u ptr提供了一种巧妙的扩展方法。它写入从该\u虚拟启用\u共享\u
这里不是存储弱\u ptr
,而是存储弱\u ptr
,其中Q
是的虚拟基类,它是从该虚拟
启用共享的,并且在虚拟基类中唯一地执行此操作。然后,它使用“成员指针或子类型shared\u ptr
constructor”非虚拟地重写this
中的shared\u和类似方法,以提供与this
中的shared\u相同的接口,在这里,您以类型安全的方式将引用计数/销毁程序组件从所拥有的资源组件中拆分
此处的开销大于此
中的基本共享\u:它具有虚拟继承并强制使用虚拟析构函数,这意味着对象存储指向虚拟函数表的指针,而从此
访问共享\u的速度较慢,因为它需要虚拟函数表调度
优点是它“只起作用”。现在继承人制度中有一个独特的shared\u from\u this
,您仍然可以获得类型安全的共享指针,指向继承自shared\u this
的类T
,您的意思是说,对于另一个与boost相关的问题,这是c++11的替代品/等价物吗?c++11。c++11版本有什么不同的地方我应该知道吗?不确定。但与链接的问答(你的问题和答案都一样)相比,这一切对我来说似乎有点狭窄。您应该尝试对此进行一些改进。我还应该说什么?至少我会给出一个完整的c++11实现要点示例。如果从这个版本中获得一个shared_将很酷,它假定对象是使用make_shared分配的(并避免继承)。我会用的@Taylor,现在我想起来了,你还必须知道它是什么类型的——如果我们有一个指向Q的指针,Q位于距离对象开始的偏移量47处,实际上是一个W,那么从Q*
中找到共享指针块是一个挑战。使用虚拟继承表可能是可行的,但我不确定。我从不使用虚拟继承,所以我喜欢一些(显然不是在std中)使普通情况变得简单的东西。即使你从不在任何地方使用new T
,你也可以使用shared\u ptr
,而不是使用make\u shared
,f.ex创建的shared\u ptr
。那些指向基子对象的。因为。。。什么?你把一件事比作<代码>无效()
。“因此,这种实现的性能不会很好”。我很高兴你有一个见解,但如果你想有效地分享这一见解(并获得赞赏,毫无疑问),最好是实际阐述它。(否则,这就像把你的餐巾纸便条交给一个图书编辑,然后说“你可以出版这个”)对吧,因为堆栈溢出在形式上相当于出版一本书。英雄联盟上面较长的答案与我所说的相呼应(“对于确实需要它的人(互斥、查找等)来说,与当前状态相比,性能受到了影响”)。exposition这个词是名词,不是动词。我感兴趣的是信息,而不是要点。Re:“正式”这不是我的意思。我指出你在这里的推理是不完整的。因此,它既没有用处(人们无法遵循您的推理来获得您的见解),也无法验证。(谢谢你纠正我的英语)@sehe好的,我添加了一个演示,所以现在可以验证了。@Taylor你明白我的意思了!(我将放弃解释
#include <memory>
#include <iostream>
#include <unordered_map>
#include <cassert>
using namespace std;
template<class T>
struct MySharedFromThis {
static unordered_map<T*, weak_ptr<T> > map;
static std::shared_ptr<T> Find(T* p) {
auto iter = map.find(p);
if(iter == map.end())
return nullptr;
auto shared = iter->second.lock();
if(shared == nullptr)
throw bad_weak_ptr();
return shared;
}
};
template<class T>
struct Holder {
weak_ptr<T> weak;
T value;
};
template<class T>
Holder<T>* GetHolder(T* p) {
// Scary!
return reinterpret_cast< Holder<T>* >(reinterpret_cast<char*>(p) - sizeof(weak_ptr<T>));
}
template<class T>
struct MyDeleter
{
void operator()(T * p)
{
delete GetHolder(p);
}
};
template<class T>
shared_ptr<T> MyMakeShared() {
auto holder = new Holder<T>;
auto p = shared_ptr<T>(&(holder->value), MyDeleter<T>());
holder->weak = p;
return p;
}
template<class T>
shared_ptr<T> MySharedFromThis(T* self) {
return GetHolder(self)->weak.lock();
}