简体   繁体   English

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

[英]Proper initialisation of smart pointers array

For such case: 对于这种情况:

    class A
    {
        //implementation
    };

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

what should I do in the B() to create an object with valid state? 我应该怎么做B()来创建一个有效状态的对象? Do I need to manually call default constructor for every A object in array? 我是否需要为数组中的每个A对象手动调用默认构造函数? And do I need to do something special in ~B() ? 我需要在~B()做一些特别的事情吗? If B class is example of bad design, feel free to say how to make it better. 如果B类是糟糕设计的例子,请随意说如何使其更好。 Thanks. 谢谢。

Edit So, here is a scheme of what I really need here. 编辑所以,这里有一个我真正需要的方案。

在此输入图像描述

So real values stored only in array of A and all other objects are for storing connections. 因此,仅存储在A和所有其他对象的数组中的实际值用于存储连接。 The easiest example - A = dot, B = Line (or curve) going via selected dots and C = a plane described by lines. 最简单的例子 - A =点,B =经过选定点的线(或曲线),C =由线描述的平面。 Hope it makes question more exact. 希望它能让问题更加准确。

To create a B object in a valid state you do not have to do anything more. 要在有效状态下创建B对象,您不必再执行任何操作。 You even do not have to declare and implement constructor and destructor for B . 您甚至不必为B声明和实现构造函数和析构函数。 std::vector<std::shared_ptr<A>> that is a member of B will be default initialized in B 's constructor which means it will not have any elements in a container yet. 作为B成员的std::vector<std::shared_ptr<A>>将在B的构造函数中默认初始化,这意味着它在容器中不会有任何元素。 It will also be properly deleted in ~B thanks to std::vector and std::shared_ptr destructors. 由于std::vectorstd::shared_ptr析构函数,它也将在~B正确删除。

On the other hand if you for example want to initialize it somehow (ie 3 values) you can use std::vector 's std::initializer_list constructor in a B 's constructor initialization list. 另一方面,如果你想以某种方式初始化它(即3个值),你可以在B的构造函数初始化列表中使用std::vectorstd::initializer_list构造函数。 For example: 例如:

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;
};

Remember that std::make_shared uses perfect forwarding so you pass A 's constructor arguments as the function arguments and not the class object itself. 请记住, std::make_shared使用完美转发,因此您将A的构造函数参数作为函数参数传递,而不是类对象本身。

Answering your concerns about the design I would like to encourage you to first think about the exclusive ownership of members in a vector before you decide to share them. 回答您对设计的疑虑我想鼓励您在决定分享之前首先考虑矢量中成员的独家所有权。

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

Above implementation is more effective on many grounds. 以上实施在许多方面更有效。 First of all it makes your design more clear on who is responsible for the lifetime of A s. 首先,它使您的设计更清楚谁负责A的生命周期。 Next std::unique_ptr is faster because it does not demand thread safe reference counting. 接下来std::unique_ptr更快,因为它不要求线程安全引用计数。 And last but not least it does not cost any additional memory (compared to regular C pointer) while std::shared_ptr may take tens of bytes (24-48) to store shared state data which is highly ineffective when you operate on small classes. 最后但并非最不重要的是,它不会花费任何额外的内存(与常规C指针相比),而std::shared_ptr可能需要几十个字节(24-48)来存储共享状态数据,这在您操作小类时非常无效。 That is why I always use std::unique_ptr as my first resort smart pointer and I only fallback to std::shared_ptr when it is really needed. 这就是为什么我总是使用std::unique_ptr作为我的第一个手段智能指针,而我只在真正需要时才回退到std::shared_ptr

EDIT: 编辑:

Answering your edit I would create 3 containers of classes A , B , C . 回答你的编辑,我会创建3个ABC类容器。 Depending of the fact if you need them to be polymorphic or not I would store either values like that (non-polymorphic types): 根据事实,如果你需要它们是多态的,我会存储这样的值(非多态类型):

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

or (polymorphic types): 或(多态类型):

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

in that order ( as must live longer than bs and bs must live longer than cs ). 按此顺序( as必须比bsbs寿命更长寿比cs更长)。 Then I would just have std::vector<A*> inside B class and std::vector<B*> inside C class without any smart pointers usage. 然后,我会只是有std::vector<A*>内部B类和std::vector<B*>内部C类没有任何智能指针的使用。

I hope that helps. 我希望有所帮助。

EDIT: 编辑:

Changed std::vector to std::deque in the first case which allows references/pointers to container elements survive containers extensions with push_back() . 在第一种情况下将std::vector更改为std::deque ,允许使用push_back()在容器元素的引用/指针中使用容器扩展。 However they will not survive erasing elements, sorting or other stuff. 然而,它们将无法在擦除元素,排序或其他东西中存活。

If you do it like that, the vector has a size of zero elements, ie the contents are trivially properly initialized. 如果你这样做,向量的大小为零元素,即内容被简单地正确初始化。 If the vector were of positive size (eg after calling resize on the vector), each of the elements would be properly initialized. 如果向量具有正大小(例如,在向量上调用resize之后),则将正确初始化每个元素。 Since the elements are shared_ptr s, the default constructor of shared_ptr would be called, which means that you would end up with a vector of empty pointers. 由于元素是shared_ptr ,因此将调用shared_ptr的默认构造函数,这意味着最终会得到一个空指针向量。

If you want to copy the contents from another container, use the iterator version of the vector constructor: 如果要从另一个容器复制内容,请使用向量构造函数的迭代器版本:

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

If you do not want to initialize the vector from a container, but from somewhere else (eg create the objects on the fly) -- write an input iterator type yourself (ie kind of a "factory iterator"). 如果你不想从容器初始化向量,而是从其他地方初始化(例如,动态创建对象) - 自己编写一个输入迭代器类型(即一种“工厂迭代器”)。

The vector is empty so you don't have to do anything special in the default constructor. 向量为空,因此您不必在默认构造函数中执行任何特殊操作。 And you don't need to do anything in B() either. 而且你也不需要在B()做任何事情。 The reference count of the shared_ptrs will be decreased automatically when the vector's destructor is called. 调用向量的析构函数时, shared_ptrs的引用计数将自动减少。

Bt default std::shared_ptr<A> will populate inner ptr with NULL . Bt default std::shared_ptr<A>将使用NULL填充内部ptr。 To create smart pointer use std::make_shared : 要创建智能指针,请使用std::make_shared

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

But in your example vector is empty. 但在你的例子中,向量是空的。

The default constructor already does everything needed. 默认构造函数已经完成了所需的一切。 You can even leave B() out without any loss. 你甚至可以毫无损失地离开B()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM