我正在研究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>
,其中包含指向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));
答案 0 :(得分: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();
但与您提出的独立模板相比,这并不一定能为您节省一些时间。
编辑:我错过了之前的回答,这似乎是一样的想法。
答案 1 :(得分:3)
我不明白这实现了什么,你似乎没有使用这个init函数获得任何额外的内存管理,而只是简单地声明一个shared_ptr。
int main( void )
{
shared_ptr<foo> a = foo::init();
shared_ptr<foo> b( new foo );
}
有什么区别。 shared_ptr提供内存管理,而不是init中的任何内容。
答案 2 :(得分:2)
似乎目标是让类的用户不可能直接调用构造函数,并且只暴露返回shared_ptr的例程。
但是如果要应用此模式,则需要在所有子类中复制它。子类不能自动“继承”init(),因此init()仍然会调用子类构造函数,因为init()不是虚方法,而是在没有对象的情况下调用。
我会像往常一样暴露构造函数,只使用标准
shared_ptr<X> x = new X();
这可以降低认知负担,可读性和灵活性。无论如何,这就是我们在公司中使用引用计数对象进行编程的方式。
答案 3 :(得分: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;
}
答案 4 :(得分:1)
为什么不在虚拟析构函数中引入公共基础,从中继承所有必需的类并简单地使用new?
答案 5 :(得分:1)
通过隐藏构造函数来强制使用shared_ptr
创建对象通常不是一个好主意。我是根据个人经验在这里与内部公司lib合作完成的。如果您想确保人们总是包装他们分配的对象,只需确保存储这些类型实例的所有参数和成员都需要shared_ptr
或weak_ptr
而不是裸指针或引用。您可能还希望从enable_shared_from_this
派生这些类,因为在共享所有对象的系统中,您必须将this
指针传递给其他对象的方法之一,并且由于它们的设计只是为了接受shared_ptr
,如果你的对象没有internal_weak_this
来确保它没有被破坏,那么你的形状会非常糟糕。
答案 6 :(得分: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,看看它是如何完成的。
答案 7 :(得分: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对象模型,但它通过实现copy-on-write(它称之为implicit sharing)进一步发展。这是为了使API行为不那么令C ++编码人员感到惊讶,他们不习惯不得不拨打clone()
。
这是通过d-pointer idiom实现的,它可以同时杀死两只鸟 - 您提供自动内存管理,和将您的实施与用户隔离开来(pimpl)
您可以在此处查看QPixmap的实际实施:qpixmap.cpp,qpixmap.h。