简体   繁体   English

为什么shared_ptr可以通过加入“受保护的访问权限”来访问

[英]why shared_ptr can access with ingoring the “protected access right”

I made some testing with shared_ptr,and i can't think out the matter below.I just started to learn the boost library. 我用shared_ptr做了一些测试,我想不出下面的事情。我刚开始学习boost库。 Is there anybody can tell me the reason? 有人可以告诉我原因吗?

#include <boost\shared_ptr.hpp>
#include <iostream>

class A 
{
public:  
    virtual void sing()
    {
        std::cout<<"A";
    }
protected:  virtual ~A() {};

};

class B : public A 
{
public:  
    virtual void sing() 
    {   
        std::cout << "B"; 
    }
    virtual ~B() {};
};


int foo()
{   
    boost::shared_ptr<A> pa(new B());
    pa->sing();

    delete static_cast<B*>(pa.get());

    delete pa.get(); //this line has a problem error C2248: “A::~A”: can't access protected memmber(declared in class“A")   
    return 0;
}

int main()
{
    foo();
    return 0;
}

but it can be compiled when that line is commented out. 但是当该行被注释掉时它可以被编译。 Surely it doesn't mean that the shared_ptr will delete the pointer internally maintained out of the main function, just like what i did. 当然,这并不意味着shared_ptr将删除内部维护的主函数之外的指针,就像我所做的那样。 Is there any difference between the pointer returned by pa.get() and the pointer internally maintained? pa.get()返回的指针和内部维护的指针之间有什么区别吗?

I believe that delete is called during destruction of the shared_ptr on the type of the pointer passed into the constructor. 我相信在传递给构造函数的指针类型的shared_ptr销毁期间会调用delete Have a look at the constructor here: 看看这里的构造函数:

http://www.boost.org/doc/libs/1_49_0/libs/smart_ptr/shared_ptr.htm#constructors http://www.boost.org/doc/libs/1_49_0/libs/smart_ptr/shared_ptr.htm#constructors

So when your pa goes out of scope, B::~B( ) is called rather than the destructor of the type contained - A::~A ( which would be impossible because it's declared protected ). 所以当你的pa超出范围时,调用B::~B( )而不是包含的类型的析构函数 - A::~A (这是不可能的,因为它被声明为protected )。

Actually, it's a bit more complicated than that: the machinery behind shared_ptr is quite complicated. 实际上,它有点复杂: shared_ptr背后的机制非常复杂。

First, let us prove there is no specific access rights granted to shared_ptr : 首先,让我们证明没有授予shared_ptr特定访问权限:

int main() {
    A* a = new B();
    std::shared_ptr<A> p(a); // expected-error
}

This will result in an error because the destructor of A is not accessible. 这将导致错误,因为无法访问A的析构函数。 Interestingly, the error occurs at the point of construction, which is a clue... 有趣的是,错误发生在构造点,这是一个线索......

So, what is the magic behind shared_ptr ? 那么, shared_ptr背后的魔力是什么?

Internally, a shared_ptr keeps much more than a simple pointer and reference counts. 在内部, shared_ptr比简单的指针和引用计数要多得多。 A shared_ptr is built with a deleter , in charge of destructing the instance of the object. shared_ptr是用deleter构建的,负责破坏对象的实例。 Where the design really shines is that this deleter is instantiated in the constructor and thus may know more type information than the bare shared_ptr type lets on. 设计真正闪耀的地方是这个deleter器在构造deleter中实例化,因此可能知道比裸shared_ptr类型更多的类型信息。

A simplified demo: 简化演示:

template <typename T>
struct shared_holder {
    typedef void (*Disposer)(T*);

    explicit shared_holder_base(T* t, Disposer d): _ptr(t), _disposer(d) {}

    void dispose() { _disposer(_ptr); _ptr = 0; }

    T* _ptr;
    Disposer _disposer;
};

template <typename U, typename T>
void dispose(T* t) { delete static_cast<U*>(t); }

template <typename T>
class shared_ptr {
    typedef shared_holder<T> holder;
public:
    shared_ptr(): _holder(0), _ptr(0) {}

    template <typename U>
    explicit shared_ptr(U* u):
        _holder(new holder(u, dispose<U, T>)), _ptr(_holder->_ptr) {}

private:
    holder* _holder;
    T* _ptr;
};

The key insight is that the disposer is instantiated from the static type known by the constructor; 关键的见解是处理器是从构造函数已知的静态类型实例化的; this is why: 这就是为什么:

  • shared_ptr<A>(new B) works shared_ptr<A>(new B)有效
  • A* a = new B; shared_ptr<A>(a) A* a = new B; shared_ptr<A>(a) does not A* a = new B; shared_ptr<A>(a)没有

You can read the Boost headers, the machinery behind the shared_ptr is quite interesting. 你可以阅读Boost标题, shared_ptr背后的机制非常有趣。

As an exercise for the reader, why does shared_ptr<T> has a _ptr member ? 作为读者的练习,为什么shared_ptr<T>_ptr成员?

When you have: 当你有:

boost::shared_ptr<A> pa(new B());

...you are calling boost::shared_ptr constructor and are dealing with TWO template parameters: ...您正在调用boost::shared_ptr构造函数并处理两个模板参数:

  1. shared_ptr template type T ( A in your case); shared_ptr模板类型T (在您的情况下为A );

    get() returns T* so when you tried: 当你尝试时, get()返回T*

     delete pa.get(); 

    ...you tried to access ~A() which is accessible only to A s children and therefore got an error. ...您尝试访问~A()这是只访问A的孩子,因此得到了一个错误。

    In the following line: 在以下行中:

      delete static_cast<B*>(pa.get()); 

    ...you were downcasting A* to B* and called delete on B* thus invoking ~B() to which you had access. ......你向下转换A*B* ,并要求删除B*从而调用~B()到你有机会访问。 ( ~B() is always calling ~A() for ~A() is declared as virtual ) ~B()总是调用~A()表示~A()被声明为virtual

  2. shared_ptr constructor argument template type Y ( B in your case) with the requirement that Y* must be convertible to T* (you can upcast B* to A* as B inherits A in your case). shared_ptr构造函数参数模板类型Y (在您的情况下为B ),要求Y*必须可转换为T* (您可以将B*向上转换为A*因为B在您的情况下继承A )。

    ~shared_ptr() calls delete on Y* ( B* in your case; ~B() can access ~A() and calls it) and this is what happens when pa goes out of scope (and this is how shared_ptr accessed base class protected destructor which was your original question). ~shared_ptr()Y*上调用delete (在你的情况下是B* ; ~B()可以访问~A()并调用它)这就是当pa超出范围时会发生的事情(这就是shared_ptr访问基类的方式)受保护的析构函数,这是你原来的问题)。

boost::shared_ptr keeps internally a single pointer. boost::shared_ptr内部保留一个指针。 When creating boost::shared_ptr you are passing to its constructor a SINGLE pointer which can be regarded as / converted to pointer to any of those TWO template argument types. 在创建boost::shared_ptr您将向其构造函数传递一个SINGLE指针,该指针可被视为/转换为指向任何这两个模板参数类型的指针。

I believe it is because the definition of the boost template declares the sharedpointer a friend of the <Class T> class from your template instantiation. 我相信这是因为boost模板的定义声明了sharedpointer是模板实例化中<Class T>类的朋友。

This is a snipet I copied from the boot shared pointer header file. 这是我从引导共享指针头文件复制的snipet。

// Tasteless as this may seem, making all members public allows member templates
// to work in the absence of member template friends. (Matthew Langston)

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS

private:

    template<class Y> friend class shared_ptr;
    template<class Y> friend class weak_ptr;


#endif

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM