智能指针数组的正确初始化

时间:2012-11-07 11:18:34

标签: c++ arrays pointers initialization

对于这种情况:

    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 =由线描述的平面。希望它能让问题更加准确。

5 个答案:

答案 0 :(得分:5)

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

另一方面,如果你想以某种方式初始化它(即3个值),你可以在std::vector的构造函数初始化列表中使用std::initializer_list的{​​{1}}构造函数。例如:

B

请记住,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更快,因为它不要求线程安全引用计数。最后但并非最不重要的是,它不需要任何额外的内存(与常规C指针相比),而std::unique_ptr可能需要几十个字节(24-48)来存储共享状态数据,这对于操作小类时非常无效。这就是为什么我总是使用std::shared_ptr作为我的第一个手段智能指针,而且只有在真正需要时才会回到std::unique_ptr

修改

回答您的修改我会创建3个容器std::shared_ptrAB。根据事实,如果你需要它们是多态的,我会存储这样的值(非多态类型):

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; 的有效期必须超过asbs的有效期必须超过bs。然后我会在cs类内部std::vector<A*>B类内部std::vector<B*>,而不使用任何智能指针。

我希望有所帮助。

修改

在第一种情况下将C更改为std::vector,允许容器元素的引用/指针在std::deque的容器扩展中生存。然而,它们不会在擦除元素,排序或其他东西中存活下来。

答案 1 :(得分:2)

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

如果要从另一个容器复制内容,请使用向量构造函数的迭代器版本:

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

如果你不想从容器初始化向量,而是从其他地方初始化(例如,动态创建对象) - 自己编写一个输入迭代器类型(即一种“工厂迭代器”)。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

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

但是在你的例子中,矢量是空的。

答案 4 :(得分:0)

默认构造函数已经完成了所需的一切。您甚至可以毫不犹豫地离开B()