C++:创建模板化共享对象而不是一个shared_ptr目的

发布于 2024-10-06 21:55:37 字数 1592 浏览 9 评论 0原文

根据我之前的问题,我希望 boost::shared_ptr 实际上是 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;
};

如果我可以创建一个模板类来为我处理所有这些事情,那就太棒了。

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 中的正确构造函数),那么我可以执行以下操作:

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) { /一些有用的算法,然后/
    删除一个; }

  2. 是否可以构建这样的模板类? (我猜你需要反射,对吧?)如果可以构建它,如何构建?

Per my previous question, I wish that a boost::shared_ptr<A> was actually a subclass of A (or perhaps A*) so that it could be used in methods that took A* as their argument.

Consider the following class:

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

In the previous question, I proposed the creation of a SharedA object to take care of this, and presumably it does.

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

It would be Grrrrrrrreat thought, if I could create a template class to take care of all of this for me.

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

If I had this, (along with the proper constructors in Shared<T>), then I could do the following:

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();

Questions:

  1. Is this useful? Or is its utility only in corner cases where you're dealing with particularly bad code. For instance:

    void aFunctionYouHaveToUse(A* a)
    {
    /some useful algorithm and then/
    delete a;
    }

  2. Is it possible to build such a templated class? (I guess you need reflection, right?) If you can build it, how?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

流云如水 2024-10-13 21:55:37

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

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

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

There's a really, darn good reason why shared_ptr does not allow explicit casting to A* (there are better ways of doing it than inheriting, which would be impossible anyway). The whole purpose of shared_ptr, and other smart pointers, are to provide a small, encapsulated object that's sole purpose is to own a pointer and to decide when and how to delete it.

If this object allowed that same pointer to just get passed around wily-nily, without thought, then it simply could not serve its purpose. Any time you dig into a smart pointer to get at the raw pointer inside you violate its ownership semantics and must then take very careful care not to go doing something stupid. Smart pointers make you think about this by forcing you to make a call to get at the pointer inside rather than just silently doing so whenever you accidentally pass it to the wrong kind of function. Think of it like the smart pointer saying, "Hey, you know what you're doing can be dangerous, right? OK then, here you go."

IMHO, the universe would be a better place if shared pointers didn't allow access to their pointers. Unfortunately, that's not this universe and can't be this universe because occasionally you still need to pass that thing into a function that doesn't use smart pointers. So, since we don't live in that better universe, OUR smart pointers do allow access, they're just not sluts about it.

时光是把杀猪刀 2024-10-13 21:55:37

也许有一种方法,但这是一种肮脏的方法。您可以尝试在层次结构中放入另一个类: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 继承,而是从他的基类型继承,该基类型具有所需的所有实现。基类需要更多的工作,但我认为这个想法非常明确。

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

Perhaps there is a way, but it's kind a dirty one. You could try to put another class in your hierarchy: ABase. A could inherit from ABase, and ABase would contain default implementations of all the public methods. Something like this:

#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;
}

This is only a concept. I need to verify code. Key idea is to pass default implementation by inheriting shared not directly from type A, but from his base type, that has all implementations needed. Base class needs some more work, but I think the idea is pretty clear.

Its not exactly what you asked for (it's actually impossible), but it could be useful in some cases, and is probably closest you can get.

辞别 2024-10-13 21:55:37

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

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

例如,使用继承:

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 类型交互时可能会出现一些复杂情况。至少,可能还需要一些代码来涵盖所有可能的用法。

Putting aside whether or not this is a good idea. If you want a shared-pointer type that can be implicitly converted to a raw pointer, you don't need to inherit from the pointee type or go through other such complications. Just make a shared-pointer type with the appropriate implicit conversion operators.

This could be done through inheritance or composition of an existing shared pointer type. (Or else by making your own shared pointer from scratch).

Using inheritance, for example:

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();
    }
};

You then use such a thing like so:

#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;
}

Of course, I haven't actually tried such a thing in a real world scenario. There might be some complications when trying to interact with corresponding weak_ptr types. At the very least, there might be some more code necessary to cover all the possible usages.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文