[英]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::vector
和std::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::vector
的std::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个
A
, B
, C
类容器。 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
必须比bs
和bs
寿命更长寿比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.