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

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.

Related

Initialize vectors and std

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.

Do I need to delete a vector?

I am defining a vector as a private variable of a class Grid. Class Points has only two instance vars that are all ints but the number of points will only be known when I read this in from the file, so I guess I have to make Points dynamically with new which means I have to destroy them later. Did I initialize constructor correctly and When writing a destructor for Grid do I need to write a destructor for vector like this: ~vecotr() or with delete or using iterator?
class Grid{
public:
// initialize vector with 3 points with val 0.
Grid(vector<Points> v) : vector<Points>(3, 0) {}; // is this right
// first option
~Grid() {
~vector<Points>(); // not sure how to destroy vector<Points>;
}
// second option
~Grid() {
delete v_points;
}
// third option
~Grid() {
for (vector<Points>::iterator it = v_points.begin(),
vector<Points>::iterator it_end = v_points.end(); it != it_end; it++)
}
private:
vector<Points> v_points;
};
Which option should I use and did I initialize constructor correctly?
If object is not allocate with new, you do not need to explicitly destroy it.
The member objects will be automatically destroyed in the reverse order of their declaration. In your case there is no need to even create a destructor as the automatic one will suffice.
If for some reason you do have member objects allocated with new, you also have to create custom copy construct and assignment operator otherwise you run into troubles of sharing the same member object across multiple instances.
I will reply because predecessors answered only to the question from topic while you are asking more questions and I will also give some advice. In the remainder of this post we will assume that if Points do allocate any dynamic memory, the memory is returned properly when Points are deleted.
Class Points has only two instance vars that are all ints but the
number of points will only be known when I read this in from the file,
so I guess I have to make Points dynamically with new which means I
have to destroy them later.
This comes with contradiction to what you actually do here
class Grid{
public:
// initialize vector with 3 points with val 0.
Grid(vector<Points> v) : vector<Points>(3, 0) {}; // is this right
private:
vector<Points> v_points;
};
because you create vector without new. However this might be OK if we assume that you first get number of Points and then you are about to create a Grid. std::vector is not C array and might be easily resized, assigned and gives much more flexibility. You do not have to create it on heap because you are afraid about size: vector elements are always created on heap, it is just a vector itself that is (if it is) on stack. And this is often exactly what we want (see i.e. RAII). The proper way to initialize a vector would be then
class Grid{
public:
// initialize vector with 3 Points with val Points(0)
Grid(vector<Points> v) : v_points(3, Points(0)) {};
private:
vector<Points> v_points;
};
Note, we do it in initialization list. For POD class members, it makes no difference, it's just a matter of style. For class members which are classes, then it avoids an unnecessary call to a default constructor.
Did I initialize constructor correctly and When writing a destructor
for Grid do I need to write a destructor for vector like this:
~vecotr() or with delete or using iterator?
You don't initialize constructor, rather in constructor initializer list you initialize class members. Since vector is not allocated with new, you will not delete it (call delete). It will be destroyed automatically when Grid is destroyed.
// fourth (and correct) option:
~Grid() {
}
Or just leave out the destructor entirely; the compiler-generated destructor will do the right thing here.
If you create an object with new you must delete it. If you don't, you mustn't.
I am assuming that Points does not have any dynamically allocated memory. If this is the case then all you need is
~Grid() { }
If it does then you need to delete that dynamically allocated memory for each item in the vector (or use smart pointers).

Stack objects being inserted into containers?

In C++ what happens if you create an object on the stack (within a function) and insert it into a heap-allocated container (which has been passed into the function/exists after the function finishes)?
The stack object has local scope, but the container it has been inserted within, is on the heap and can last after the function (where the insert was made) has returned. Is the stack object still retrievable from the container after the function returns?
void Test( std::vector<MyClass>& myvec )
{
MyClass m;
myvec.push_back(m);
}
In this particular case, m will be copy-constructed into a new instance of MyClass, which will be owned by the vector. So a different but equivalent instance of MyClass can be retrieved from the vector, yes.
Base assumption: when you use Vector, you really mean std::vector. The answer could change with a container that's designed enough differently.
As long as you do like you usually should, and store objects (not pointers) in the container, you're all right, because what's stored in the container is normally a copy of the object you pass.
Under the right circumstances, the object in the container can be move constructed from what you pass, but the effect is basically the same -- you end up with an object whose lifetime continues until it's removed from the container (or the container is destroyed, etc.)
Is the stack object still retrievable from the container after the function returns?
Yes, your myvec.push_back(m); makes a copy of m and a new copy is manged by vector.
However, after your function returns myvec doesn't have m inside because you pass myvec into Test function by value, Test function makes a temporary copy of myvec and copy m into it, after function returns the temporary copy of myvec is released. So you meant to pass myvec to Test function by reference as below:
public void Test(Vector<MyClass>& myvec){
MyClass m;
myvec.push_back(m);
}
As noted by other answers, m is copied into vector. That said, your function receives vector by value too (UPD: it was true for the original code, which was edited since), and it's obviously not what you wanted.
The code in the question will create a copy of MyClass in the std::vector. The original m will be destructed when the Test method exits.
If we change the vector to store pointers to MyClass we have two possible options.
void Test( std::vector<MyClass*>& myvec )
{
// Allocates a new MyClass on the heap.
MyClass* pM = new MyClass();
myvec.push_back(pM);
// This variable will be allocated on the stack and cleaned up on method exit
MyClass dontDoThis;
myvec.push_back(&dontDoThis);
}
At the end of this method myvec has two elements, myvec[0] and myvec[1].
When a container of pointers is stored then the object must be allocated so that it is valid for the length of time the pointer is in the container. In the example above the pM pointer will be valid after the Test method exits. This means that myvec[0] will be a valid pointer after the method exits.
Initially, a valid pointer to dontDoThis variable will be added to the vector, but when the method exits the destructor of dontDoThis will be called and the memory will probably be used to store other data. The pointer in myvec looks ok, but any attempt to actually use it will cause undefined behaviour. On method exit the pointer in myvec[1] might look valid, but actually it points to junk.
Note that at a later time, when myvec[0] is changed or deleted, it is important to call:
delete myvec[0]
to ensure that the object is cleaned up properly. Otherwise a memory leak will occur.
After explaining what will happen with naked pointers, I strongly recommend you use smart pointers such as std::unique_ptr and std::shared_ptr
Is the stack object still retrievable from the container after the function returns?
Only if MyClass has a "gut" copy constructor. (Deep copy or sharing ownedship of other resuorses, etc)
I mean, it could be retrived but it could be in a broked state

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.

C++ destructor issue with std::vector of class objects

I am confused about how to use destructors when I have a std::vector of my class.
So if I create a simple class as follows:
class Test
{
private:
int *big;
public:
Test ()
{
big = new int[10000];
}
~Test ()
{
delete [] big;
}
};
Then in my main function I do the following:
Test tObj = Test();
vector<Test> tVec;
tVec.push_back(tObj);
I get a runtime crash in the destructor of Test when I go out of scope. Why is this and how can I safely free my memory?
The problem is you don't define a copy constructor for Test. So the compiler generates a default copy constructor for you, which just copies the content of the object - in this case the int pointer.
Now, when you push back your object into the vector, it is implicitly copied with the copy constructor. Which results in two objects pointing to the same array of ints! So in the end, two destructors try to delete the same array - BANG.
Whenever you define a class which owns members via pointers*, apart from the destructor you must also define a copy constructor for it. Update: and an assignment operator, for the same reason (thanks #James :-)
Update2: A trivial way to get around all these restrictions is to define a static array instead of the dynamically allocated one:
class Test
{
private:
int big[10000];
// no need for constructors, destructor or assignment operator
};
However, the best practice is to use std::vector<int> instead of an array.
* that is, contains pointers to members with ownership semantics (thanks to #Steve Jessop for clarification)
Your problem is here:
Test tObj = Test();
The Test() creates a temporary Test object, which then gets copied to tObj. At this point, both tObj and the temporary object have big set to point to the array. Then the temporary object gets destroyed, which calls the destructor and destroys the array. So when tObj gets destroyed, it tries to destroy the already-destroyed array again.
Further, when tVec is destroyed, it will destroy its elements, so the already-destroyed array will be destroyed yet again.
You should define a copy constructor and an assignment operator so that when a Test object gets copied, the big array gets copied, or has some sort of reference count so that it doesn't get destroyed until all owners are destroyed.
An easy fix is to define your class like this:
class Test
{
private:
std::vector<int> big;
public:
Test (): big(10000) {}
};
In this case, you wouldn't need to define any destructor, copy constructor, or assignment operator, because the std::vector<> member will take care of everything. (But note that this means 10,000 integers get allocated and copied whenever you copy an instance of Test.)
Without a copy-constructor, the vector will create a flat copy of your object. This leads to two objects of type Test referencing the same array big. The first instance deletes the array when it gets destroyed, and then the second instance try to dereference a deleted pointer, which is undefined behavior.
Test tObj = Test();
This is wrong and should be as it does not create copies:
Test tObj;
This also create a lot of copies:
vector<Test> tVec;
tVec.push_back(tObj);
So if you free one int array, you'll free all the arrays. And the following delete will fail.
What you need is either:
use a copy constructor to have for each class a separate array
Why use a pointer?
class Test
{
private:
int big[10000];
public:
};
This will work fine.