1

我正在研究 C++ 框架,并希望将自动内存管理应用于许多核心类。到目前为止,我有标准的方法是

class Foo 
{

public:

  static
  shared_ptr<Foo> init() 
  {
    return shared_ptr<Foo>(new Foo);
  }

  ~Foo() 
  {
  }

protected:

  Foo()
  {
  }

};


// Example of use
shared_ptr<Foo> f = Foo::init();

但是,当我将 Foo 子类化时,上面的内容就中断了,因为即使 thoinit()是继承的,它仍然返回shared_ptr<Foo>包含指向实例的指针Foo

谁能想到一个优雅的解决方案?我是否应该坚持使用(半)手动包装类的实例shared_ptr?这也可以在不声明新的命名构造函数的情况下公开参数化构造函数......

IE。

template <typename T>
shared_ptr<T> make_shared(T* ptr)
{
  return shared_ptr<T>(ptr)
}

// Example
shared_ptr<T> 
  f1 = make_shared(new Foo()),
  f2 = make_shared(new Foo(1,2));
4

8 回答 8

4

我会尝试这样的事情:

template<class T>
class creator
{
  public:
    static shared_ptr<T> init()
    {
      return(shared_ptr<T>(new T));
    }
};

class A : public creator<A>
{
};

class B : public A, public creator<B>
{
  public:
    using make_shared<B>::init;
};

// example use
shared_ptr<A> a = A::init();
shared_ptr<B> b = B::init();

但是,与您提出的独立模板相比,这不一定能为您节省一件事。

编辑:我错过了以前的答案,这似乎是同一个想法。

于 2009-02-12T09:11:10.917 回答
2

我不明白这实现了什么,你似乎没有使用这个 init 函数获得任何额外的内存管理,而不是简单地声明一个 shared_ptr。

int main( void )
{
    shared_ptr<foo> a = foo::init();
    shared_ptr<foo> b( new foo );
}

有什么不同。shared_ptr 提供内存管理,而不是 init 中的任何内容。

于 2009-02-12T09:36:11.823 回答
2

似乎目标是使类的用户无法直接调用构造函数,并且只公开一个返回 shared_ptr 的例程。

但是如果你想应用这个模式,你需要在所有的子类中复制它。子类不能自动“继承” init(),因此 init() 仍会调用子类构造函数,因为 init() 不是虚拟方法,并且在没有对象的情况下调用。

我会让构造函数像往常一样暴露,只使用标准

shared_ptr<X> x = new X();

这使认知负担低、易读且保持灵活。无论如何,这就是我们在公司中使用引用计数对象编程的方式。

于 2009-02-12T18:07:22.220 回答
1

怎么样...

template<typename Derived>
class Foo 
{
public:

    static shared_ptr<Derived> init() 
    {
        return shared_ptr<Derived>(new Derived);
    }

    ~Foo() 
    {
    }

protected:

    Foo()
    {
    }

};


class Bar : public Foo<Bar>
{
};

int _tmain(int argc, _TCHAR* argv[])
{
    shared_ptr<Bar> b = Foo<Bar>::init(); 
    return 0;
}
于 2009-02-12T08:54:09.070 回答
1

为什么不引入一个带有虚拟析构函数的公共基础,从中继承所有必要的类并简单地使用 new 呢?

于 2009-02-12T09:35:24.710 回答
1

shared_ptr通过隐藏构造函数来强制创建对象通常不是一个好主意。我是根据个人经验与一个内部公司库一起工作的,这正是这样做的。如果你想确保人们总是包装他们分配的对象,只要确保所有存储这些类型实例的参数和成员都期望一个shared_ptrweak_ptr而不是一个裸指针或引用。您可能还想从 派生这些类enable_shared_from_this,因为在所有对象都共享的系统中,在某些时候您必须将this指针传递给这些其他对象的方法之一,并且由于它们被设计为仅接受shared_ptr,如果您的对象无法internal_weak_this确保它不会被破坏,那么您的状态就很糟糕。

于 2009-02-12T20:27:18.153 回答
0

您需要在整个层次结构的每种类型中使用静态工厂函数。

class Foo
{
public:
    static shared_ptr< Foo > instantiate( /* potential arguments */ )
    {
           return shared_ptr< Foo >( new Foo( /* potential arguments */ );
    }

// blah blah blah
};

class Bar : public Foo
{
public:
    static shared_ptr< Bar > instantiate( /* potential arguments */ )
    {
           return shared_ptr< Bar >( new Bar( /* potential arguments */ );
    }

// blah blah blah
};

如果您仍然有任何困惑,请在 sourceforge 上搜索 CppCodeProvider 并查看它是如何完成的。

于 2009-02-12T17:56:18.423 回答
0

顺便说一句,在大型 C++ 框架中,对编码器隐藏“自动内存管理”是很常见的。这让他可以编写更短更简单的代码。例如,在 Qt 中,您可以这样做:

QPixmap foo() {
    QPixmap pixmap(10, 10);
    return pixmap;
}

void bar() {
    QPixmap a = foo(); // no copying occurs, internal refcount incremented.
    QPixmap b = a;     // ditto.
    QPainter p(&b);
    p.drawPoint(5, 5); // data can no longer be shared, so a copy is made.
    // at this point 'a' is still unchanged!
    p.end();
}

像 Qt 中的许多东西一样,这模仿了 Java 对象模型,但它通过实现写​​时复制(它称为隐式共享)更进一步。这是为了让不习惯调用clone().

这是通过d-pointer idiom实现的,它用一块石头杀死两只鸟 - 您提供自动内存管理,并将您的实现与用户 ( pimpl ) 隔离。

您可以在此处查看 QPixmap 的实际实现:qpixmap.cppqpixmap.h

于 2009-12-29T11:15:45.210 回答