2012-11-07 98 views
5

的正确初始化对于这样的情况:智能指针数组

class A 
    { 
     //implementation 
    }; 

    class B 
    { 
    public: 
     B(); 
     ~B(); 
    private: 
     std::vector<std::shared_ptr<A>> _innerArray; 
    }; 

我应该在B()做创建具有有效状态的对象?我是否需要为数组中的每个A对象手动调用默认构造函数?我是否需要在~B()做一些特别的事情?如果B级是糟糕设计的例子,可以随意说出如何让它变得更好。谢谢。

编辑 因此,这里是我真正需要的方案。

enter image description here

仅存储在A的阵列和所有其他对象所以实值是用于存储连接。 最简单的示例 - A =点,B =通过选定点进行的线(或曲线)和C =通过线描述的平面。希望它使问题更加确切。

+1

完美检查:你需要指针吗?如果是这样,它应该是一个共享指针? –

+0

B类应该有权访问但不拥有其他地方存储的某些对象。我没有看到在这里使用unique_ptr而不是shared_ptr,但我是智能指针的noob。 –

+0

@Pavel你是对的:你的场景排除使用'unique_ptr',它强制使用指针。但是,如果'B'不应该拥有所有权,我甚至会考虑使用原始指针而不是共享指针。毕竟,后者表示共享所有权(但也许这就是你最终需要的)。 –

回答

4

要在有效状态下创建B对象,您不必再做任何事情。您甚至不必为B声明和实现构造函数和析构函数。 std::vector<std::shared_ptr<A>>B的成员将在B的构造函数中默认初始化,这意味着它在容器中还没有任何元素。由于std::vectorstd::shared_ptr析构函数,它也将在~B中正确删除。

另一方面,如果你想例如初始化它(即,3值),您可以在B的构造函数初始化列表中使用std::vectorstd::initializer_list构造函数。例如:

class B 
{ 
public: 
    B(): _innerArray{ std::make_shared<A>(), 
         std::make_shared<A>(), 
         std::make_shared<A>() } {} 
    ~B() {} 
private: 
    std::vector<std::shared_ptr<A>> _innerArray; 
}; 

记住std::make_shared使用完美转发,所以你通过A的构造函数的参数作为函数的参数,而不是类对象本身。

回答您对设计的关注我想鼓励您在决定分享之前首先考虑向量中成员的独占所有权。

class B 
{ 
public: 
    B(); 
    ~B(); 
private: 
    std::vector<std::unique_ptr<A>> _innerArray; 
}; 

以上实施方式在许多方面更为有效。首先,它让你的设计更清晰地说明谁是负责A的使用寿命。 Next std::unique_ptr更快,因为它不需要线程安全引用计数。最后但并非最不重要的是它不会花费任何额外的内存(与普通的C指针相比),而std::shared_ptr可能需要几十个字节(24-48)来存储共享状态数据,这对于小型操作时非常无效。这就是为什么我总是使用std::unique_ptr作为我的第一款度假智能指针,而当它真的需要时,我只能退回到std::shared_ptr

编辑:

回答您的编辑我将创建的类AB 3个容器,C。根据这一事实,如果你需要他们多态与否我将存储一样,要么值(非多态类型):

std::deque<A> as; 
std::deque<B> bs; 
std::deque<C> cs; 

或(多态类型):

std::vector<std::unique_ptr<A>> as; 
std::vector<std::unique_ptr<B>> bs; 
std::vector<std::unique_ptr<C>> cs; 
的顺序

as必须比bs长,bs必须长于cs)。然后我只需里面的B类和std::vector<B*>里面的C类没有任何智能指针的使用。

我希望有帮助。

编辑:

在其允许的引用第一壳体改变std::vectorstd::deque /指针容器元素生存容器与扩展push_back()。然而,他们将无法生存擦除元素,排序或其他东西。

+0

很棒的回答。完善。 –

2

如果你这样做,矢量的大小为零,即内容被正确地初始化。如果矢量大小正确(例如,在矢量上调用resize之后),则每个元素都将被正确初始化。由于元素是shared_ptr s,将会调用shared_ptr的默认构造函数,这意味着您最终将得到一个空指针向量。

如果你想将内容从另一个容器复制,使用矢量构造函数的迭代版本:

B (SomeContainerTypeContainingSharedPointers container) 
: _innerArray (container.begin(), container.end()) { 
} 

如果您不想初始化从容器的载体,而是从别的地方(例如,快速创建对象) - 自己编写一个输入迭代器类型(即,一种“工厂迭代器”)。

1

该向量为空,因此您不必在默认构造函数中执行任何特殊操作。而且你也不需要在B()中做任何事情。当向量的析构函数被调用时,shared_ptrs的引用计数将自动减少。

1

Bt默认std::shared_ptr<A>将用NULL填充内部ptr。要创建智能指针使用std::make_shared

_innerArray.push_back(std::make_shared<A>(/*constructor params here*/)); 

但在你的例子向量是空的。

0

默认构造函数已经完成了所有需要的操作。你甚至可以离开B()没有任何损失。