2

根据我之前的问题,我希望 aboost::shared_ptr<A>实际上是A(或可能A*)的子类,以便它可以用于A*作为参数的方法中。

考虑以下类:

class A
{
public:
    A(int x) {mX = x;}
    virtual void setX(int x) {mX = x;}
    virtual int getX() const {return mX;}
private:
    int mX;
};

在上一个问题中,我建议创建一个 SharedA 对象来处理这个问题,并且大概确实如此。

class SharedA : public A
{
public:
    SharedA(A* a) : mImpl(a){}
    virtual void setX(int x) {mImpl->setX(x);}
    virtual int getX() const {return mImpl->getX();}
private:
    boost::shared_ptr<A> mImpl;
};

如果我可以创建一个模板类来为我处理所有这些,那将是 Grrrrrrrreat 的想法。

template <class T>
class Shared : public T
{
public:
    SharedT(T* t) : mImpl(t)
    {
    //What kind of crazy voodoo goes here?
    }

private:
    boost::shared_ptr<T> mImpl;
};

如果我有这个(以及正确的构造函数Shared<T>),那么我可以执行以下操作:

A* indestructo_A = new Shared<A>(new A(100));
A* indestructo_A_clone = new Shared<A>(indestructo_A);
delete indestructo_A
cout << "Indestructo-A back with a vengence!" << indestructo_A_clone.getX();

问题:

  1. 这有用吗?还是仅在您处理特别糟糕的代码的极端情况下才实用。例如:

    void aFunctionYouHaveToUse(A* a) { /一些有用的算法然后/
    删除 a; }

  2. 是否可以构建这样的模板类?(我想你需要反思,对吧?)如果你能建造它,怎么建造?

4

3 回答 3

8

shared_ptr 不允许显式转换为 A* 有一个非常好的理由(有比继承更好的方法,这无论如何都是不可能的)。shared_ptr 和其他智能指针的全部目的是提供一个小型封装对象,其唯一目的是拥有一个指针并决定何时以及如何删除它。

如果这个对象不加思索地允许同一个指针巧妙地传递,那么它根本无法达到其目的。每当您深入研究智能指针以获取内部的原始指针时,您都违反了它的所有权语义,并且必须非常小心,不要做一些愚蠢的事情。智能指针通过强迫您调用获取内部指针而不是在您不小心将它传递给错误类型的函数时默默地这样做,从而让您考虑这一点。把它想象成智能指针在说:“嘿,你知道你在做什么可能很危险,对吧?好吧,给你。”

恕我直言,如果共享指针不允许访问它们的指针,宇宙将是一个更好的地方。不幸的是,这不是这个宇宙,也不能是这个宇宙,因为偶尔你仍然需要将那个东西传递给一个不使用智能指针的函数。所以,既然我们并不生活在那个更好的宇宙中,我们的智能指针确实允许访问,他们只是不喜欢它。

于 2010-12-10T17:25:50.690 回答
1

也许有一种方法,但它是一种肮脏的方法。您可以尝试在您的层次结构中放置另一个类:ABase。A 可以从 ABase 继承,并且 ABase 将包含所有公共方法的默认实现。像这样的东西:

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

class ABase
{
    public:
        ABase() {}
        void init( ABase *a ) { mImpl.reset( a ); }

        virtual void setX( int x ) { mImpl->setX( x ); }
        virtual int getX() const { return mImpl->getX(); }

        boost::shared_ptr< ABase > mImpl;
};

class A : public ABase
{
public:
    typedef ABase BaseClass;

    A(int x) {mX = x;}
    virtual void setX(int x) {mX = x;}
    virtual int getX() const {return mX;}
private:
    int mX;
};


template <class T>
class Shared : public T::BaseClass
{
public:
    Shared(T* t) { init( t ); }
};

int main()
{
    Shared< A > sh( new A( 1 ) );

    std::cout << sh.getX() << std::endl;
    sh.setX( 5 );
    std::cout << sh.getX() << std::endl;
}

这只是一个概念。我需要验证代码。关键思想是通过不直接从类型 A 而是从他的基类型继承 shared 来传递默认实现,这具有所需的所有实现。基类需要更多的工作,但我认为这个想法很清楚。

它并不完全符合您的要求(实际上是不可能的),但在某些情况下它可能很有用,并且可能是您可以获得的最接近的。

于 2010-12-10T17:22:56.393 回答
0

先不管这是否是个好主意。如果您想要一个可以隐式转换为原始指针的共享指针类型,则不需要从指针类型继承或经历其他类似的复杂情况。只需使用适当的隐式转换运算符创建一个共享指针类型。

这可以通过继承或组合现有的共享指针类型来完成。(或者通过从头开始制作自己的共享指针)。

使用继承,例如:

template<typename T>
class convertible_shared_ptr : public boost::shared_ptr<T>
{
public:
    convertible_shared_ptr() {}
    convertible_shared_ptr(T* ptr) : boost::shared_ptr<T>(ptr) {}

    operator T* () const
    {
        return get();
    }

    T* operator-> () const
    {
        return get();
    }
};

然后你使用这样的东西:

#include <iostream>
#include <boost/shared_ptr.hpp>
using namespace std;

class A    // simple class for example purposes
{
public:
    A() : member(42) {}

    int member;
};

void foo(A* a)
{
    cout << "a->member=" << a->member << endl;
}

int main()
{
    convertible_shared_ptr<A> ptr(new A);

    foo(ptr);

    cout << "ptr->member=" << ptr->member << endl;

    return 0;
}

当然,我实际上并没有在现实世界的场景中尝试过这样的事情。尝试与相应weak_ptr类型交互时可能会出现一些复杂情况。至少,可能需要更多代码来涵盖所有可能的用法。

于 2010-12-10T18:14:50.990 回答