命名构造函数和继承
我正在研究 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我会尝试这样的事情:
但是与您建议的独立模板相比,这不一定能为您节省一些东西。
编辑:我错过了之前的答案,这似乎是相同的想法。
I would try something like this:
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.
我不明白这会实现什么,与简单地声明一个shared_ptr相比,使用这个init函数似乎没有获得任何额外的内存管理。
有什么不同。 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.
What's the difference. shared_ptr provides the memory management, not anything in init.
看起来目标是使类的用户无法直接调用构造函数,而仅公开返回shared_ptr的例程。
但如果你想应用这个模式,你需要在所有子类中复制它。 子类不能自动“继承”init(),因此init()仍会调用子类构造函数,因为init()不是虚拟方法,并且在没有对象的情况下调用。
我将像往常一样将构造函数暴露出来,只使用标准,
这可以降低认知负担,具有可读性,并且保持灵活性。 无论如何,这就是我们在公司中使用引用计数对象进行编程的方式。
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
This keeps cognitive burden low, is readable, and remains flexible. This is how we program in our company with reference counted objects, anyway.
怎么样...
How about...
为什么不引入带有虚拟析构函数的公共基类,从中继承所有必需的类并简单地使用 new 呢?
Why not introduce a common base with a virtual destructor, inherit all necessary classes from it and simply use new?
通过隐藏构造函数来强制使用
shared_ptr
创建对象通常不是一个好主意。 我是根据与一个内部公司库合作的个人经验来发言的,该库正是这样做的。 如果您想确保人们始终包装他们分配的对象,只需确保存储这些类型实例的所有参数和成员都需要shared_ptr
或weak_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 ashared_ptr
orweak_ptr
instead of a naked pointer or reference. You might also want to derive these classes fromenable_shared_from_this
, because in a system where all objects are shared, at some point you'll have to pass thethis
pointer to one of these other objects' methods, and since they're designed only to acceptshared_ptr
, you're in pretty bad shape if your object has nointernal_weak_this
to ensure it isn't destroyed.您需要在整个层次结构的每种类型中使用静态工厂函数。
如果您仍然有任何困惑,请在 sourceforge 上搜索 CppCodeProvider 并看看它是如何完成的。
You need the static factory function in every type of the entire hierarchy.
If you still have any confusion, please search CppCodeProvider on sourceforge and see how its done there.
顺便说一句,在大型 C++ 框架中,向编码人员隐藏“自动内存管理”是很常见的。 这让他可以编写更短、更简单的代码。 例如,在 Qt 中你可以这样做:
像 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:
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.