自动实例化的智能指针

时间:2010-12-15 15:25:17

标签: c++ smart-pointers composition coupling

我正在寻找一种简单的方法来减少C ++项目中的头部耦合,这主要是由于(过度使用)类组合,这当然需要完整的类型。例如:

// header A
class A
{
  B b; // requires header B
};

我也考虑过接口和pimpl,但两者都暗示了一些我不想手动编写/支持的样板代码(或者有没有办法让它自动化?)。

所以我考虑用指针和前向替换成员class B* pB;,但这需要处理对象的创建和删除。好的,我可以使用智能指针进行删除(不是auto_ptr,因为它在创建时需要完整的类型,所以请说shared_ptr<class B> pB;),但现在如何创建对象?

我可以在A的构造函数中创建对象,如pB = new B;,但这又是手动的,更糟糕​​的是,可能有几个构造函数......所以我在寻找有关自动执行此操作的方法,这可以像在B b;的定义中将autoobjptr<class B> pB;更改为A一样简单,而无需费心pB实例化。

我很确定这不是一个新想法,所以也许你可以给我一个共同解决方案或讨论的参考?

更新:为了澄清,我不打算打破AB之间的依赖关系,但我想避免包含B标题,其中一个包含A的标题。在实践中,B用于A的实现,因此一个典型的解决方案是为A创建一个接口或pimpl,但我现在正在寻找更容易的东西。

UPDATE2:我突然意识到一个懒惰的指针,例如建议的here会做的伎俩(太糟糕了,没有标准的实现,比如说升级),当与虚拟结合时析构函数(允许不完整类型)。我仍然不明白为什么没有标准的解决方案,并且想要重新发明轮子......

UPDATE3:突然之间,Sergey Tachenov带来了一个非常简单的解决方案(接受的答案),虽然我花了半个小时才明白为什么它真的有用...... 如果删除A()构造函数或在头文件中将其定义为内联,魔法将不再起作用(compliation错误)。我想当你定义一个显式的非内联构造函数时,成员的构造(甚至是隐式构造)是在完成类型B的同一编译单元(A.cpp)内完成的。另一方面,如果您的A构造函数是内联的,则成员的创建必须在其他编译单元中进行,并且由于B在那里不完整而无法工作。嗯,这是合乎逻辑的,但现在我很好奇 - 这个行为是由C ++标准定义的吗?

UPDATE4:希望最后更新。有关上述问题的讨论,请参阅接受的答案和评论。

5 个答案:

答案 0 :(得分:3)

答案 1 :(得分:1)

我很确定这可以通过实现unique_ptr的方式实现。不同之处在于allocated_unique_ptr构造函数默认会分配B对象。

但是请注意,如果要自动构造B对象,使用默认构造函数进行实例化。

答案 2 :(得分:0)

嗯,你自己给出了最好的解决方案,在构造函数中使用指针和new ......如果有多个构造函数,那么在那里重复那些代码。你可以创建一个为你做这个的基类,但这只会使实现神秘化......

您是否考虑过class B中的模板?这也可以解决你的标题交叉依赖关系,但是可能会增加你的编译时间......这就是我们试图避免这些#include的原因。你有没有测量编译时间?这令人不安吗?这是问题吗?

更新:模板方式示例:

// A.h
template<class T>
class A
{
public:
    A(): p_t( new T ) {}
    virtual ~A() { delete p_t }
private:
    T* p_t;
};

同样,这很可能不会增加编译时间(B.h需要被拉入以创建模板实例A<B>),它确实可以让你删除A头中的包含和源文件。

答案 3 :(得分:0)

您可以编写一个自动pimpl_ptr<T>,它会自动删除,删除和复制包含的T.

答案 4 :(得分:0)

您的方法存在的问题是,虽然您可以避免以这种方式包含B的头文件,但它并没有真正减少依赖性。

减少依赖关系的更好方法是让B派生自在单独的头文件中声明的基类,并在A中使用指向该基类的指针。您仍然需要手动创建正确的后代(B)当然,在A的构造函数中。

A和B之间的依赖关系也很可能是真实的,在这种情况下,你通过人工避免包含B的头文件来改善一切。