Initialize vectors and std - c++

If I have a var
vector<myClass> myVector;
Is it already initialized?, ie, may I add (push_back) inmediately elements or I should call the constructor in the following way?
myVector = vector<myClass>();
On the other hand, is it the same std::vector<myClass> and vector<myClass>?

Is it already initialized?
Yes (assuming this is std::vector). As with any sane class, all its constructors (including the default constructor used here) put it into a well-defined state. At this point, it's a valid, empty vector.
I should call the constructor in the following way?
That's not calling the constructor (at least, not on myVector). Constructors are called automatically during object initialisation; there's no way to call it a second time. This creates another empty vector, then copy-assigns it to myVector.
On the other hand, is it the same std::vector and vector?
Presumably, this is std::vector, dumped into the global namespace with an evil using namespace std;. To avoid doubt, confusion and potential amibiguity, you should avoid doing that, remove any rogue using-directives, and always refer to it as std::vector.

In this case
vector<myClass> myVector;
there is no need to call default constructor separately.
You can call push_back and other methods.

The notation
MyClassType a;
actually calls MyClassType's default constructor, if it has one. So yes, a vector is already initialized and ready to use.
Your second snippet:
myVector = vector<myClass>();
Actually creates a new, temporary vector, which is default constructed, and then calls myVector's copy assignment operator operator=().
In this regard, C++ is different from many other languages. For example, in Java, you'd need to do MyClassType a = new MyClassType(). This is not necessary in C++. Whenever you declare a value of class type with automatic storage1, the object is automatically default constructed. This is also true for class members. Let's say you have:
class A {
std::vector<int> m_myVector;
};
Then there is no need to initialize m_myVector - it's done automatically whenever you instantiate an object of class A.
It's different when you allocate objects on the heap:
// Note: DON'T use raw pointers in actual code - use smart pointers instead.
// Just for illustration purposes.
// This is just a pointer to an A, it's not yet initialized.
A* myA;
myA = new A();
// now myA points to a heap allocated, default constructed A object.
// Note that you can omit the default constructor's `()` and just write:
myA = new A;
Heap allocating an object is actually closer to what Java does under the hood. Anyway, when writing proper C++, you rarely need to heap allocate, and you wouldn't ever do it with a vector.
1 Automatic storage: Put simply, anything you create in C++ without using new/delete or similar.

Related

Why doesn't initializing a std::vector<T> initialize T?

Why is the default constructor for A not called when I initialize an std::vector like so?
std::vector<A> vec; //Doesn't call constructor
vec.push_back(A(2)); //Calls constructor
I don't understand this, can somebody explain in great detail please?
When you construct vector v it contains no A objects (so there is no need to call a constructor). As you populate v, you explicitly construct A objects and these are then copy or move constructed into the memory in the vector.
There are never any default constructed A objects, so the default constructor is never called (your code would compile fine if you marked it = delete).
The line:
std::vector<A> vec;
initializes a std::vectorm not an A. Although it holds instances of A is hasn't been initialized in a way that would cause instances of A to be created.
When you create a vector<A>, you only initialize the underlying vector infrastructure, with enough memory to hold a bunch of A element, but no A is initialized at that time, so no A ctor has to be called.
When you push back a (temporary) A(25), the temporary is first created from its simple ctor, then it is copied (or moved) in the vector internal array, and destroyed.
That explains the order and time of apparition of your messages.

Initialization after deletion of constructor

My question is this: after deleting a constructor is there any way to initialize a class? For example
class A{
public:
A() = delete;
int a = 42;
int fun(){
a += 1;
return a;
}
};
Now it should not be possible to use this class. For example you cannot:
A* instance = (A*)malloc(sizeof(A));
instance->fun(); //segfault
and
A instance; //compile error undefined function
Assuming for some strange reason you actually wanted to use the class with the constructor deleted is there a way that you could do it? That is without doing something like overriding the constructor.
I know this is a strange question, but I am interested in knowing if someone has a (perhaps obscure) way of doing this. Thanks!
If the class is an aggregate you can create one using aggregate initialization, which does not call a constructor of A. For example:
A a = { 1 };
In C++11 your class was not an aggregate because of the presence of the = 42. So in C++11 your class is unusable.
But in C++14 this was changed, and = 42 does not prevent the class being an aggregate, so it is usable again.
The reason this is allowed is that calling malloc is not equivalent to calling new. malloc merely allocates memory and returns where it begins; new allocates and constructs an object. Just directly creating an A, as in A instance;, runs the constructor as well - so it expects it to be there.
As such, it is not an error as you never actually construct any A object. You allocate uninitialized memory, cast the pointer to A*, and then call it. This is valid because the language and the compiler don't care (or likely know) where you got that memory. All it knows is that at runtime, instance contains valid allocated memory; if that were not the case, it might segfault (it also might not, but would still probably be bad).
What happens when you actually run this is that fun() will access uninitialized memory as if it were an A; as such, int a will be something, but probably not 42.
It's not required that a pointer be to a constructable class. For example, you can cast an actual class pointer to one of its non-constructable interface classes and still access it. Effectively, the same methodology that allows that allows this.

Vector of structs containing objects

I'll have a large struct containing basic types, STL objects (std::string) as well as objects of a library class (which I can't modify).
struct Info {
string name;
int number;
LibClass object;
// ...
}
I'll want to stuff instances of this struct into a vector and then create a function to fill this vector.
vector<Info> list;
void addElement (string myName, int myNumber, LibClass myObject /*, ... */)
{
Info newElement = { myName, myNumber, myObject /*, ... */};
list.push_back(newElement);
}
The above code will fail, because the LibClass does not have an assigment operator specified which is needed by the vector implementation.
The code will work if I change my struct (and the addElement function parameter) to hold a pointer to a LibClass object instead. But then I would have to do memory management outside of my function (create an LibClass object on the heap for every new element).
Next best thing is to do the memory management inside the addElement function by creating a copy of the given stack object on the heap, which would keep my calling code clean. But as this code is not part of another object, I have no destructor where I could free the memory again.
Is there a way to implement this without having to do memory allocation outside of this code AND without blowing this up to be a full featured factory class?
Update: I can't modify the library class, I'm not able to use C++11 or helper libs such as boost. The structs will basically be read-only inside the vector. Even the vector will be only filled once, then only read access will happen.
If I understood everything correctly, you may think of using std::shared_ptr<>. You'll be able to allocate the library dynamically, but freeing will be done automatically.
I thought of replacing LibClass object; with std::shared_ptr<LibClass> object; and instantiating LibClass inside addElement function. Info will be copyable, because shared_ptr can move and copy itself - each copy will still hold reference to the same LibClass instance. And on the other side, when you delete all instances of a single Info item (no matter how), the shared_ptr will take care of deleting LibClass instance as well. Think of shared_ptr as a way to dynamically create class and then leave it for automatic memory management.
Since std::shared_ptr<> is part of C++11, if you cannot use the latter, you can use its equivalent from Boost: boost::shared_ptr<>. If that's also not an option, you can implement a version of shared pointer yourself - an example.
You obviously already have a copy constructor, otherwise pass-by-value would fail. So vector growth ought not to be a problem (though you may have to avoid removing elements from the start or middle of the vector).
For construction, you may use emplace_back in C++11.

How does std::vector allocate objects?

How does std::vector allocate objects? It would seem as if it just uses std::allocator::allocate to create a block of memory, but then never calls std::allocate::construct. Is this true? Does std::vector only allocate memory and never construct the objects as memory allocation?
What if there is no default constructor? How is the constructor called when there is no default constructor on the object? What if there is more than one parameter?
For example, with this code there is no default constructor and std::allocator allows it.
#include <vector>
using namespace std;
class A{
protected:
int m;
public:
explicit A(int a) : m(a) { }
};
int main(){
vector<A> test;
return 0;
}
This has rather changed since C++11.
In C++03, construct could only perform copy-construction in-place.
However, note that std::vector in particular is an array of objects, but there is a distinct size and capacity. That is, there can be more empty elements beyond the end of the part of the array that contains useful data.
That is why the standard library's allocator has a separation between "construction" and "memory allocation." The allocator does do both, but not at the same time. This allows std::vector to allocate more memory than it uses. When you add new elements, it doesn't necessarily have to allocate more memory; it can just use the spare memory it has left over via a call to allocator::construct.
Also, note that all of the C++03 functions that add elements to std::vector take an element as a parameter. push_back, insert, even the sized constructor takes as a value as an argument. Yes, it's a default parameter, but it still takes a value as an element. This element is copied into the vector, using a call to the allocator's construct method which takes a copy.
In C++11, standard containers are required to use the allocator_traits<>::construct function. This is a varadic function that forwards its parameters to the actual construct. This traits function will (by default. It can be specialized) call the allocator::construct method if that call is well-formed. If it isn't, it will try placement new.
This allows for the new emplace functions to work.
But yes, the objects contained in standard library containers are in fact constructed objects. Even if the allocator's construct method is not called.
It's implementation dependent, but a typical implementation uses std::allocator::allocate to allocate the block of memory, and then uses the placement new to construct, via the copy constructor (or move constructor in C++11), the instances.
When elements are erased, their destructors are directly invoked to destroy the objects, even if the underlying memory isn't released.

Vector as a class member

Hello I have this question:
I would like to have a vector as class member. This is perhaps my question
easier for you and I apologize for that.
how should I declare the vector? And is this correct? std::vector<int> *myVector; or std::vector<int> myVector ?
how should I handle this vector in dealloc?
How can I initialize the array into a if?
Is this correct?
if(myCondition)
{
if(!myVector) //is this correct?
myVector = new std::vector<int>(); //is this correct? on this i have a error
}
You most certainly want to use std::vector<int> myVector. No need to initialize it, as it gets automatically initialized in the constructor of your class and deallocated when your class is destroyed.
Just use automatic allocation: declare it as a member like this:
class YourClass
{
std::vector<int> myVector;
// ...
};
The array gets constructed automatically before any of your constructor is run and is destroyed automatically when your object is deallocated, you don't need to care about it (also, the default copy constructor and assignment operator will handle copying gracefully automatically).
If, instead, you want to create the array only after a particular condition, you have to resort to a (smart) pointer and dynamic allocation, but IMHO it's quite cumbersome (especially because you then have to get right the "big three" - copy constructor, assignment operator, destructor); you could instead simply allocate the vector with automatic allocation and use a separate flag to mark your array as not initialized, or just check if its size is 0.
That depends entirely on context - what the vector means and why you need it. Should it be shared among multiple objects? If you don't know, don't keep a pointer, go with your second option.
std::vector<int> myVector;
If you have strong reasons to have a pointer, then please use a smart pointer, the one that provides most appropriate ownership for your situation - shared_ptr, scoped_ptr, unique_ptr or whatever_ptr
Most of the time, when we use standard library, We do not need to care about the memory allocation/deallocation. The template will handle it automatically. eg. The memory of a std::vector will be increase or decrease according to the elements stored in this vector. This would be an example.
Therefore, almost you can use it this way in your case.
std::vector<int> myVector //your second declaration
if(myCondition)
{
myVector.push(some_int); // use it directly
}
The memory the vector used will be deallocated when the Class object you created is destroyed.