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.
Related
I come from a C background. I used to allocate memory/array, for example, sending it to somewhere else, and the pointer stayed there, even after, the scope where it was allocated was destroyed.
Now, if I do the same with vectors : initialize, pass it by reference, and then keep that reference saved somewhere. After the initial method, that actually created the vector, goes out of scope, would it be destroyed ? Or as the pointer to it is still saved, it will be kept.
std::vector frees the memory it holds when it is destroyed. Holding a reference to an object that gets destroyed is very bad. Accessing it is UB. General rule: Do not store references, only use them where you can be sure that the object exists for the entire scope, e.g. as parameter of a function.
If you want to keep a copy of the data, simply copy the std::vector. No reference needed.
If you want to be able to access the data from different locations, and have it live as long as at least one location still has a reference/pointer to it, don't use std::vector, use std::shared_ptr.
If you want to combine the benefits of std::vector with the benefits of shared memory that lives until the last place lets go of it, combine them: std::shared_ptr<std::vector<...>>.
If you want to have the std::vector live in one place for a bit, and then live in another place but not in the first place anymore, use move semantics:
std::vector<int> foo = {1, 2, 3};
std::vector<int> bar = std::move(foo); // bar now holds the data that foo held, foo is empty, no copy was performed
A pointer to an array on the stack will not keep the array alive, I suppose thats the same in C. Now a vector is not an array. It is a wrapper around a heap allocated array which frees the memory of the array when it goes out of scope.
... because a pointer to it is still saved it will still be kept?
No! A pointer or reference to a std::vector will not keep the vector alive. The canonical wrong example is:
std::vector<T>& foo() {
std::vector<T> x;
return x;
} // baaam !
The reference returned from the function is dangling. YOu cannot do anything with it. The correct way would be to return by value and rely on return value optimization:
std::vector<T> foo() {
std::vector<T> x;
return x;
}
If you do:
auto y = foo();
No copying is involved, thanks to NRVO.
PS: Compilers should warn you about returning a reference to a local variable.
No if I do the same with vectors, I initialize a vector, pass it by reference, then keep the reference saved somewhere. After the initial method that actually created the vector goes out of scope, would it be destoryed?
Yes.
or because a pointer to it is still saved it will still be kept?
No.
You can have dangling pointers in C++ just like you can in C. It's exactly the same.
This is also often the case for references (though in some cases the lifetime of the object is extended for a little bit).
It is true that the vector's data is internally managed by the vector, but that's by-the-by since you're asking about the vector itself. Forget the vector and ask the same question about an int, then you'll realise the answer is just as you'd expect it to be in C.
The existing answers are good, will add here:
block A
{
vector<int> my_vec(10, 0);
//...something...
}
block B
The my_vec vector will go out of scope and be destroyed at the closing bracket. Now that's stl (Standard Template Library) vectors.
You can also use C-style arrays (but with different syntax). For very large arrays, I have found the allocation time with a dynamically-allocated array to be faster than STL vectors.
//static, goes out of scope and memory handled at the end of code block
int arr0[10];
//dynamic, not destroyed unless delete called.
int* arr1 = new int[10];
//...work with arr1...
delete [] arr1;
Just like in C, you need to take care of de-allocating any memory you create using new.
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.
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.
I have a std::vector of Element*. When will the destructor be called.
How is it different if it is a vector of Element
std::vector<Element*> vect;
..
struct Element
{
Record *elm;
Element(Record *rec)
{
elm = new Record();
//...copy from rec
}
~Element()
{
delete elm;
}
};
I am using the vector as follows:
Element *copyElm = new Element(record);
vect.push_back(copyElm);
In the above code, how can I ensure there's no leak.
You could use a reference-counting pointer-wrapper class in your array, and the items will automatically get deleted whenever there are no more references to them. One such class is boost::shared_ptr. You will also find it in some compiler's shipping C++ libraries because it is being added to a future version of C++.
std::vector<boost::shared_ptr<Element> > vect;
These classes wrap operator ->, etc, so you can use them in most of the same ways that you'd used a normal pointer.
http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/shared_ptr.htm
Whenever you free the class Element instance yourself. The vector will free the vector elements (the pointers), but not the class Element objects pointed to. After all, the vector has no way to know if you have other pointers to the same object.
vector will call release the memory of the object it is holding (i.e. pointers) but will not release the memory of the object it is pointing to. You need to release the memory of the Element object yourself. If it was a vector<Element> then whenever you do a push_back a copy of the element is inserted into the vector. vector guarntess that it will release the memory allocated to this copied object. But be aware with the current definition of Element you will get a seg fault as you have not defined the copy ctor and assignment operator.
EDIT
If you for some reason don't want to use smart pointers, then only option is to write a release function which goes through the entire vector and calls the delete on the stored pointer.
In a vector of Element, the destructor is called a lot. Whenever a node is assigned, the vector is sized down, the vector has to move in memory, or the vector goes out of scope/is destroyed, destructors are called on the elements before they are changed/discarded. Also, the copy constructor is called for assignment, and the default constructor is called to initialize each entry. Sorting such a vector will involve a lot of both copying and destroying.
In a vector of Element* it is never called, unless you call delete yourself.
Take a look at Boost shared_ptr for a saner solution, or unique_ptr if you have a compiler with relatively new features.
Destroying a pointer is always a no-op, and there are several good reasons why.
The folowing constructor
std::vector<Object> objects(n);
creates n objects calling the default constructor, i.e. something like that:
std::vector <Object> objects;
for (unsigned int i = 0; i < n; i++) objects.push_back(o);
Is this procedure also valid for dynamically allocated objects? Does the construction
std::vector<Object *> objects(n);
represent this functionality?
std::vector <Object*> objects;
for (unsigned int i = 0; i < n; i++) objects.push_back(new Object());
If not, is there a way how to arrange it?
std::vector<Object> objects(n);
The behavior of this depends on which version of the C++ Standard your Standard Library implementation implements:
In C++03, this creates one default constructed Object and then copy constructs that object n times.
In C++0x, this default constructs n Objects.
The difference shouldn't usually matter, but it's good to know.
std::vector<Object *> objects(n);
This creates a vector with n null Object*s in it. Since Object* is not a class type and does not have a constructor, the newly inserted objects are value initialized, which for pointers means they are set to NULL.
If you want to dynamically create new objects and then store pointers to them in the container, you need to call new yourself. Note that you should not be storing raw pointers in a standard library container if the container owns the pointed-to objects. Doing so is not exception safe.
You should be using a smart pointer like shared_ptr or unique_ptr instead (note: the auto_ptr smart pointer cannot be stored in containers due to its unusual copy semantics, thus shared_ptr or unique_ptr should be used).
In any case, to insert pointers to n distinct, dynamically allocated objects into the container, you need to call new n times to create those n objects. There's nothing wrong with your for loop solution.
The folowing constructor
std::vector<Object> objects(n);
creates n objects calling the default constructor
Yes, but the default constructor is used only to construct the second optional parameter to the constructor of vector, the n objects in the vector are constructed by copying this parameter. [C++03 answer]
If you did something like:
std::vector<Object*> objects(n, new Object());
you would dynamically allocate one object and have n pointers to that object in your vector which is probably not what you want.
It is almost always a bad idea to use a container of pointers if that container is supposed to own the dynamically allocated objects. You should consider something like boost::ptr_vector, or if that is not possible a container of smart pointers (not std::auto_ptr, though).
No, the vector won't be automatically created with pointers to Object instances. You will have to perform the for loop you have written in order to populate it correctly.
You will also need to delete each of these objects when you have finished with them too.
Your final code example has the right general idea, but tread carefully: vector will not manage the allocations for you if you do that! objects.clear() will leak memory, for instance.
You probably want to use std::vector<some_smart_ptr<Object> > instead, but choosing the right smart pointer class requires care and attention to (for instance) what happens when you copy elements from one vector to another. boost::shared_ptr is a safe choice, but may have unnecessary overhead for your use case. boost::ptr_vector may be better.