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> >


A
shared\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;
    }
};
这同样是非常低的成本,并且可以很好地处理简单的案例。最后,我们的开销比a
T
的基线成本低一个
弱的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();
}