Proper initialisation of smart pointers array - c++

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.

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 As. 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 do it like that, the vector has a size of zero elements, i.e. the contents are trivially properly initialized. If the vector were of positive size (e.g. after calling resize on the vector), each of the elements would be properly initialized. Since the elements are shared_ptrs, the default constructor of shared_ptr would be called, which means that you would end up with a vector of empty pointers.
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 (e.g. create the objects on the fly) -- write an input iterator type yourself (i.e. 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. The reference count of the shared_ptrs will be decreased automatically when the vector's destructor is called.

Bt default std::shared_ptr<A> will populate inner ptr with NULL. To create smart pointer use 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.

Related

Is it possible to store an unique_ptr both in class and vector in C++?

I am trying to hold a unique pointer to both a vector (from a Base class) and a Derivated class object, so later I am able to call a method for all. However I want to call aswell methods from Derivated classes so I need to store the reference for them aswell.
class Foo
{
vector<unique_ptr<Base>> bar;
unique_ptr<Derivated1> bar2;
unique_ptr<Derivated2> bar3;
}
Foo::Foo(){
this->bar2 = make_unique<Derivated1>();
this->bar2->doSomethingDerivated1();
this->bar3 = make_unique<Derivated2>();
this->bar->push_back(move(bar2));
this->bar->push_back(move(bar3));
}
Foo::callForAll() {
for (const auto& foo: this->bar) foo->doSomethingBase();
}
Foo::callForDerivated1() {
this->bar2->doSomethingDerivated1();
}
Is something like this possible? For my understanding this code will most likely fail. Will move place bar2 and bar3 to nullptr? Creating a unique_ptr, store a raw pointer with bar2->get() and then push_back to vector works?
Note: These objects only belong to this class, so unique would make sense.
No. The whole point of unique_ptr is to be unique. This means you cannot copy it.
However, you CAN make copies of the underlying pointer that unique_ptr manages. E.g.
unique_ptr<Foo> foo(new Foo);
Foo* foo_copy = foo.get();
There are a couple things that you need to be careful of when doing this:
Do not delete foo_copy. That is the job of unique_ptr. If you delete foo_copy, then you will have committed the sin of double delete, which has undefined behavior (i.e. the compiler is allowed to generate code that launches a nuclear missile).
Do not use foo_copy after foo has been destroyed because when foo is destroyed, the underlying pointer is deleted (unless foo has relinquished ownership of the underlying pointer, and the underlying pointer hasn't been deleted by some other means yet). This is the sin of use after free, and it also has UB.
Moving is one way for unique_ptr to relinquish ownership. Once you move out of a unique_ptr, it no longer points to anything (that is the whole point of moving; when you walk from A to B, you are no longer at A, because there is only one of you, and you have decided to instead be located at B). I believe that trying to call a method using the -> operator on an empty unique_ptr is also UB.
It seems like what you should do is
vector<unique_ptr<Base>> v;
Derived* ob = v[i].get();
Let me reiterate that this is slightly dangerous and unusual.
Tangent: I find it highly suspicious that you are not using virtual methods; virtual really should be the default (kind of like how double is the default, not float, even though float looks like it is and should be the default). Actually, I find it suspicious that you are using inheritance. Inheritance is one of the most over-rated features of all time. I suspect that this is where your troubles may be originating. For example, the Go language doesn't even have inheritance, yet it does have polymorphism (i.e. different implementations of the same interface).
PS: Please, do not accidentally extinguish the human race by invoking UB.

What happens when using pass by reference and member initialization lists in C++ classes?

Okay, so I have a large vector say
vector<vector<vector<int>>>
of 10000 by 10000 by 10000.
I have a class which has such a vector as a private member variable:
class foo {
private:
vector<vector<vector<int>>> myvector
};
I have a constructor for my class that uses pass by reference and initializer list:
foo(vector<vector<vector<int>>> &myvector_in) : myvector(myvector_in);
I want to know what's exactly happening in terms of memory usage. Is the private myvector the same as the one that was originally declared, or is it a copy.
Basically, I want to know if there are ever two version of myvector in memory.
Thank You!
Here is a fishing tip.
Fairly easy to answer yourself. Set [0][0][0] of myvector_in to a known value. Invoke the constructor and inside it also set [0][0][0] but of myvector to a different value. Once the constructor has returned, print the content of myvector_in. If it's the same as the one you original set you must conclude that the two vectors are different entities, thus one was copied into a different one. If they are the same than you can conclude they are in fact the same instances.
You could also print addresses to get a better sense of what's what.
I must point out, the memory requirement mention in your original question are in the realm of super computer, you got one?
You have a member of type vector<vector<vector<int>>> and initialize it with another vector<vector<vector<int>>>. How would it be possible not to have said data twice in memory? Thats more a matter of logic than a matter of c++.
Alternatives
You could store a pointer vector<vector<vector<int>>>* or a reference vector<vector<vector<int>>>& to the vector in an appropriate class member. Or use one of the smart pointers to do so. In any of these cases some serious thinking about memory management is a good idea.
Or you use a move constructor, which is moving the passed in vector in your member vector.
using vec = std::vector<std::vector<std::vector<int>>>;
class foo {
public:
foo() = delete;
foo(const vec&) = delete;
foo(vec&& myvector_in) : myvector(std::move(myvector_in)) {};
private:
vec myvector;
};
Of course that will render that argument passed to the constructor useless but that a trivial consequence of the not-copying you want.
You can pass your vector to that constructor if you first cast it to an rvalue using std::move:
foo my_foo(std::move(test));
The easy way of addressing this issue in C++11 (and newer) is to accept the constructor argument by value:
struct foo {
using vec=std::vector<std::vector<std::vector<int>>>; // from DrSvanHay
foo(vec v) : myvector(std::move(v)) {}
private:
vec myvector;
};
Surprisingly, this actually minimizes copies:
If the client has a vector cv;, cv gets copied into the parameter v, but that copy was necessary to have cv and foo::myvector upon completion.
If the client passes std::move(cv), cv gets moved into v and there is no copy.
If the client passes make_vector(...), the parameter v is move-initialized from the return value (or, in C++17, is the return value).
(In all these cases, v is then moved into foo::myvector, of course.)

Better to instantiate object with correct values and then push to vector, or instantiate, push to vector then set correct values?

Say I have a class like so:
class Foo{
Foo* otherFooObj;
Foo* otherFooObj2;
.....
};
Would it better to:
A.
Acquire the correct values for member variables (addresses for otherFooObj and otherFooObj2, etc.) using functions
Instantiate (construct) a Foo object with those correct values.
Push the object to a vector.
OR
B.
Instantiate a Foo object with dummy values (dummy addresses for otherFooObj and otherFooObj2)
Push the object to a vector.
Use functions to set the Foo object's member variables to correct values once it sits inside the vector.
OR
C.
Instantiate a Foo object with dummy values
Use functions to acquire correct values and set Foo's member variables to those values
Push the object to a vector.
Right now, I'm thinking there isn't much difference between any of these design patterns, and that it doesn't matter which flow I follow. But I would like to get more opinions on this, and want to know if there are any other factors I'm overlooking and I should consider (which I feel like there are, maybe with pointers and such).
The question is a bit too generic to be answered appropriately. A good design goal is to only have objects in a valid state, by some definition of valid in your design. The alternative is not to be able to trust that an object is in a valid state before hand, and that will complicate your live and lead you to situations in which by mistake a half-baked object lives around.
From that point of view, I would create the values for the members and call a constructor that moves the object from a non-existent to that valid state.
In your case, it seems that you are building a self-referential data structure: a graph, a tree or something alike. If that is the case, it might be that a Foo with the two members set to nullptr make sense and you could consider the alternatives, but I would still provide a constructor that enables you to set the object to a full state:
class Foo {
Foo *a, *b;
public:
Foo() : a(), b() {} // initialize both to nullptr, assuming this is a *valid* state
Foo(Foo *a, Foo *b) : a(a), b(b) {}
...
};
Coming back to the original question, I would opt to create the values for the members and emplace into the vector:
Foo *a = f();
Foo *b = f();
vector.emplace_back(a, b);
Avoid generating an invalid state. If you're not setting the member pointers, then at least you must set them to nullptr. If possible, generate a useful and valid state as soon as possible (unless that is expensive, when instead you might want use lazy initialisation, but still a valid though incomplete initial state). Thus, if you can obtain the final correct values for the members, then set them immediately.
If those pointers own any memory (are initialised from freshly allocated memory), then you must be very careful. You should actually use std::unique_ptr<> in this case and move your object, or even better directly construct in its vector position via vector::emplace_back().
Also, if you know the total number of object in advance, you may want to vector::reserve() enough space prior to putting objects in the vector.

When do we need to define destructors? [duplicate]

This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 8 years ago.
I read that destructors need to be defined when we have pointer members and when we define a base class, but I am not sure if I completely understand. One of the things I am not sure about is whether or not defining a default constructor is useless or not, since we are always given a default constructor by default. Also, I am not sure if we need to define default constructor to implement the RAII principle (do we just need to put resource allocation in a constructor and not define any destructor?).
class A
{
public:
~Account()
{
delete [] brandname;
delete b;
//do we need to define it?
};
something(){} =0; //virtual function (reason #1: base class)
private:
char *brandname; //c-style string, which is a pointer member (reason #2: has a pointer member)
B* b; //instance of class B, which is a pointer member (reason #2)
vector<B*> vec; //what about this?
}
class B: public A
{
public something()
{
cout << "nothing" << endl;
}
//in all other cases we don't need to define the destructor, nor declare it?
}
The rule of Three and The Rule of Zero
The good ol' way of handling resources was with the Rule of Three (now Rule of Five due to move semantic), but recently another rule is taking over: the Rule of Zero.
The idea, but you should really read the article, is that resource management should be left to other specific classes.
On this regard the standard library provides a nice set of tools like: std::vector, std::string, std::unique_ptr and std::shared_ptr, effectively removing the need for custom destructors, move/copy constructors, move/copy assignment and default constructors.
How to apply it to your code
In your code you have a lot of different resources, and this makes for a great example.
The string
If you notice brandname is effectively a "dynamic string", the standard library not only saves you from C-style string, but automatically manages the memory of the string with std::string.
The dynamically allocated B
The second resource appears to be a dynamically allocated B. If you are dynamically allocating for other reasons other than "I want an optional member" you should definitely use std::unique_ptr that will take care of the resource (deallocating when appropriate) automatically. On the other hand, if you want it to be an optional member you can use std::optional instead.
The collection of Bs
The last resource is just an array of Bs. That is easily managed with an std::vector. The standard library allows you to choose from a variety of different containers for your different needs; Just to mention some of them: std::deque, std::list and std::array.
Conclusion
To add all the suggestions up, you would end up with:
class A {
private:
std::string brandname;
std::unique_ptr<B> b;
std::vector<B> vec;
public:
virtual void something(){} = 0;
};
Which is both safe and readable.
As #nonsensickle points out, the questions is too broad... so I'm gonna try to tackle it with everything I know...
The first reason to re define the destructor would be in The Rule of Three which is on part the item 6 in Scott Meyers Effective C++ but not entirely. The rule of three says that if you re defined the destructor, copy constructor, or copy assignment operations then that means you should rewrite all three of them. The reason is that if you had to rewrite your own version for one, then the compiler defaults will no longer be valid for the rest.
Another example would be the one pointed out by Scott Meyers in Effective C++
When you try to delete a derived class object through a base class pointer and the base class has a non virtual destructor, the results are undefined.
And then he continues
If a class does not contain any virtual functions, that is often an indication that it is not meant to be used as a base class. When a class is not intended to be used as a base class, making the destructor virtual is usually a bad idea.
His conclusion on destructors for virtual is
The bottom line is that gratuitously declaring all destructors virtual is just as wrong as never declaring them virtual. In fact, many people summarize the situation this way: declare a virtual destructor in a class if and only if that class contains at least one virtual function.
And if it is not a Rule Of three case, then maybe you have a pointer member inside your object, and maybe you allocated memory to it inside your object, then, you need to manage that memory in the destructor, this is item 6 on his book
Be sure to check out #Jefffrey's answer on the Rule of Zero
There are precisely two things that necessitate defining a destructor:
When your object gets destructed, you need to perform some action other than destructing all class members.
The vast majority of these actions once was freeing memory, with the RAII principle, these actions have moved into the destructors of the RAII containers, which the compiler takes care of calling. But these actions can be anything, like closing a file, or writing some data to a log, or ... . If you strictly follow the RAII principle, you will write RAII containers for all these other actions, so that only RAII containers have destructors defined.
When you need to destruct objects through a base class pointer.
When you need to do this, you must define the destructor to be virtual within the base class. Otherwise, your derived destructors won't get called, independent of whether they are defined or not, and whether they are virtual or not. Here is an example:
#include <iostream>
class Foo {
public:
~Foo() {
std::cerr << "Foo::~Foo()\n";
};
};
class Bar : public Foo {
public:
~Bar() {
std::cerr << "Bar::~Bar()\n";
};
};
int main() {
Foo* bar = new Bar();
delete bar;
}
This program only prints Foo::~Foo(), the destructor of Bar is not called. There is no warning or error message. Only partially destructed objects, with all the consequences. So make sure you spot this condition yourself when it arises (or make a point to add virtual ~Foo() = default; to each and every nonderived class you define.
If none of these two conditions are met, you don't need to define a destructor, the default constructor will suffice.
Now to your example code:
When your member is a pointer to something (either as a pointer or a reference), the compiler does not know ...
... whether there are other pointers to this object.
... whether the pointer points to one object, or to an array.
Hence, the compiler can't deduce whether, or how to destruct whatever the pointer points to. So the default destructor never destructs anything behind a pointer.
This applies both to brandname and to b. Consequently, you need a destructor, because you need to do the deallocation yourself. Alternatively, you can use RAII containers for them (std::string, and a smart pointer variant).
This reasoning does not apply to vec because this variable directly includes a std::vector<> within the objects. Consequently, the compiler knows that vec must be destructed, which in turn will destruct all its elements (it's a RAII container, after all).
If you dynamically allocate memory, and you want this memory to be deallocated only when the object itself is "terminated", then you need to have a destructor.
The object can be "terminated" in two ways:
If it was statically allocated, then it is "terminated" implicitly (by the compiler).
If it was dynamically allocated, then it is "terminated" explicitly (by calling delete).
When "terminated" explicitly using a pointer of a base-class type, the destructor has to be virtual.
We know that if a destructor is not provided, the compiler will generate one.
This means that anything beyond simple cleanup, such as primitive types, will require a destructor.
In many cases, dynamic allocation or resource acquisition during construction, has a clean up phase. For example, dynamically allocated memory may need to be deleted.
If the class represents a hardware element, the element may need to be turned off, or placed into a safe state.
Containers may need to delete all of their elements.
In summary, if the class acquires resources or requires specialized cleanup (let's say in a determined order), there should be destructor.

Deep-copying a structure containing reference members (C++)

I have a C++ class that contains objects that have reference members pointing to other objects within the class. This seemed like a good idea at the time, but now I need to implement a deep copy of the whole thing, and I can't see a way to do that that doesn't feel like a clunky hack.
A simplified version of my code looks like this. The question is about writing a copy constructor for A.
class C {
int x, y, z; // nothing complicated stored in this class
public:
// constructor and other methods
};
class B {
C &c1;
C &c2;
public:
// constructor and other methods
};
class A {
C *c_array;
B *b_array; // for each item in this array,
// its 'c1' and 'c2' fields point to members of c_array.
public:
// constructor and other methods
};
A few people have asked how this structure is initialised, so please let me stress that this is irrelevant for answering the question. The initialisation will always satisfy the requirement that the reference members of the items in b_array point to items in c_array, but beyond that the data could be anything. It is important that the copy constructor work for any data that satisfies this property. This is not a problem that can be solved by reusing the existing initialisation code.
The problem is that if I just copy the objects in b_array, their reference members will point to the C objects in the old instance of A. I need to make them point to the corresponding items in the new instance. The only way I can think to do that is this:
for each element of b_array, get the address that its reference member points to, and store that in a pointer
work out the index into the array that that pointer corresponds to using pointer arithmetic
use this index to initialise the reference member of the corresponding element of the new b_array.
My question is, is there a cleaner / simpler / more elegant way? If there isn't, I will just refactor my design to use array indices instead of references throughout.
Perhaps I shouldn't have used reference members - I know some people say it's always better to use pointers. If I had used pointers instead of references, would there be a better solution to this problem? (I can't see one but I don't know.)
A deep copy using references will have to first copy the values (c_array) and then store references to those new values. I cannot see a way of achieving this other than the algorithm you describe.
Using pointers instead of references will not change this. There are various comparisons of pointers vs references. Pointers are less tricky to initialise (create as null and assign when you are ready) and more dangerous to use (might still be null). But you will still have to copy the objects, then find + copy the links to them.
I cannot see a simpler / more elegant way than using array indices. With array indices you will just copy the arrays value by value, and the structure of which index points to which object will be taken care of for you.
You can provide an assignment operator (and a copy ctor) for A that deals with the change of both c_array and b_array in tandem, assuming that B can handle the assignment of C as just a reference/pointer update.
It can be along the lines of:
struct B { ... B& operator=(const C& c) { this->c = &c; return *this; } };
struct A { ...
A& operator=(const A& a) {
c_array = a.c_array;
b_array = a.b_array;
// re-assign pointers/references only using B's `operator=(const C&)` :
std::copy_n(c_array.begin(), c_array.size(), b_array.begin());
return *this;
}
};
A bit messy, but: see live example
Note that if you comment out the std::copy_n line, you can of course observe in the output that the copy isn't detached, that is, the b_array of the copy points to the original's c_array instead of its own.