命名构造函数和继承

发布于 2024-07-14 01:49:46 字数 781 浏览 9 评论 0原文

我正在研究 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 时,上面的方法会中断,因为即使 init() 被继承,它仍然返回 shared_ptr其中包含指向 Foo 实例的指针。

有人能想出一个优雅的解决方案吗? 我是否应该坚持使用 shared_ptr (半)手动包装类的实例? 这也使得能够公开参数化构造函数,而无需声明新的命名构造函数......

即。

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

I'm working on C++ framework and would like to apply automatic memory management to a number of core classes. So far, I have the standard approach which is

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

However, the above breaks when I subclass Foo, since even tho init() is inherited, it still returns shared_ptr<Foo> which contains a pointer to instance of Foo.

Can anyone think of an elegant solution to this? Should I perhaps just stick with (semi-)manually wrapping instances of class with shared_ptr? This would also give ability to expose parameterized constructors without declaring new named constructors...

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

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

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

发布评论

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

评论(8

手心的海 2024-07-21 01:49:46

我会尝试这样的事情:

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

但是与您建议的独立模板相比,这不一定能为您节省一些东西。

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

I would try something like this:

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

But this isn't necessarily saving you a thing compared to standalone template you proposed.

Edit: I missed previous answer, this seems to be the same idea.

救赎№ 2024-07-21 01:49:46

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

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

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

I don't understand what this achieves, you don't appear to be getting any extra memory management using this init function than by simply declaring a shared_ptr.

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

What's the difference. shared_ptr provides the memory management, not anything in init.

伴随着你 2024-07-21 01:49:46

看起来目标是使类的用户无法直接调用构造函数,而仅公开返回shared_ptr的例程。

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

我将像往常一样将构造函数暴露出来,只使用标准,

shared_ptr<X> x = new X();

这可以降低认知负担,具有可读性,并且保持灵活性。 无论如何,这就是我们在公司中使用引用计数对象进行编程的方式。

It seems that the goal is to make it impossible for users of the classes to call the constructors directly, and only expose a routine which returns shared_ptr's.

But if you want to apply this pattern, you need to replicate it in all the subclasses. The subclasses cannot automatically "inherit" init() so that init() would still call the subclass constructor, because init() is not a virtual method and is called without an object.

I would leave the constructors exposed as usual and just use the standard

shared_ptr<X> x = new X();

This keeps cognitive burden low, is readable, and remains flexible. This is how we program in our company with reference counted objects, anyway.

纵情客 2024-07-21 01:49:46

怎么样...

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

How about...

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;
}
萌酱 2024-07-21 01:49:46

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

Why not introduce a common base with a virtual destructor, inherit all necessary classes from it and simply use new?

始终不够 2024-07-21 01:49:46

通过隐藏构造函数来强制使用 shared_ptr 创建对象通常不是一个好主意。 我是根据与一个内部公司库合作的个人经验来发言的,该库正是这样做的。 如果您想确保人们始终包装他们分配的对象,只需确保存储这些类型实例的所有参数和成员都需要 shared_ptrweak_ptr 而不是裸指针或参考。 您可能还想从 enable_shared_from_this 派生这些类,因为在所有对象都是共享的系统中,在某些时候您必须将 this 指针传递给以下对象之一:这些其他对象的方法,并且由于它们被设计为仅接受 shared_ptr,因此如果您的对象没有 internal_weak_this 来确保它不存在,那么您的情况会非常糟糕被毁了。

It's generally not a good idea to force creation of objects using shared_ptr by hiding the constructors. I'm speaking from personal experience here working with an internal company lib that did exactly that. If you want to ensure people always wrap their allocated objects, just make sure that all arguments and members which store instances of these types expect a shared_ptr or weak_ptr instead of a naked pointer or reference. You might also want to derive these classes from enable_shared_from_this, because in a system where all objects are shared, at some point you'll have to pass the this pointer to one of these other objects' methods, and since they're designed only to accept shared_ptr, you're in pretty bad shape if your object has no internal_weak_this to ensure it isn't destroyed.

那小子欠揍 2024-07-21 01:49:46

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

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 并看看它是如何完成的。

You need the static factory function in every type of the entire hierarchy.

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

If you still have any confusion, please search CppCodeProvider on sourceforge and see how its done there.

策马西风 2024-07-21 01:49:46

顺便说一句,在大型 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 对象模型,但它通过实现 copy-on-write (它称为

这是通过d-pointer 惯用语实现的,一举两得Stone - 您提供自动内存管理,并且将您的实现与用户隔离(粉刺)。

您可以在这里查看 QPixmap 的实际实现: qpixmap.cpp, qpixmap .h

By the way, in large C++ frameworks it's common to hide the "automatic memory management" from the coder. This lets him write shorter and simpler code. For example, in Qt you can do this:

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

Like many things in Qt, this mimics the Java object model, but it goes further by implementing copy-on-write (which it calls implicit sharing). This is intended to make the API behavior less suprising to C++ coders, who aren't used to having to call clone().

This is implemented via the d-pointer idiom, which kills two birds with one stone - you provide automatic memory management, and you insulate your implementation from the user (pimpl).

You can look at the actual implementation of QPixmap here: qpixmap.cpp, qpixmap.h.

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