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? Do I need to manually call default constructor for every A
object in array? And do I need to do something special in ~B()
? If B class is example of bad design, feel free to say how to make it better. 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. The easiest example - A = dot, B = Line (or curve) going via selected dots and C = a plane described by lines. Hope it makes question more exact.
If you want to create a unique_ptr , you can write: class Object { }; // unique_ptr auto ptr = std::make_unique<Object>(); auto intPtr = std::make_unique<int>(); // or shared_ptr auto shared = std::make_shared<Object>(); auto intShared = std::make_shared<int>();
In C++, a smart pointer is implemented as a template class that mimics, by means of operator overloading, the behaviors of a traditional (raw) pointer, (e.g. dereferencing, assignment) while providing additional memory management features.
What are the main features of smart pointers in C++ in general? a) They employ garbage collection to manage memory allocation and deallocation. b) They support both exclusive and shared ownership of objects and memory. c) They know whether they are the last owner of a resource.
To create a B
object in a valid state you do not have to do anything more. You even do not have to declare and implement constructor and destructor for 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. It will also be properly deleted in ~B
thanks to std::vector
and std::shared_ptr
destructors.
On the other hand if you for example want to initialize it somehow (i.e. 3 values) you can use std::vector
's std::initializer_list
constructor in a B
's constructor initialization 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.
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. Next std::unique_ptr
is faster because it does not demand thread safe reference counting. 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. 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.
EDIT:
Answering your edit I would create 3 containers of classes 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
). Then I would just have std::vector<A*>
inside B
class and std::vector<B*>
inside C
class without any smart pointers usage.
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()
. However they will not survive erasing elements, sorting or other stuff.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With