Is this correct?:
std::vector<Enemy*> enemies;
enemies.push_back(new Enemy());
Enemy* enemy = enemies[0];
enemies.erase(enemies.begin() + 0);
delete enemy;
It works, yes, but it's not an ideal approach.
Firstly, adding 0 is just noise, you can remove that. But even better, just use pop_front(). Also, no need for the intermediate step, you can delete before removing.
But std::vector isn't good as popping from the front, especially if it's large (because the remaining elements need to be shifted to fill the void). If you don't need contiguous memory, use a std::deque instead. Or, if order doesn't matter, you can use something like this:
template <typename T, typename A>
void unordered_pop_front(std::vector<T, A>& vec)
{
using std::swap;
swap(vec.front(), vec.back()); // constant time
vec.pop_back(); // constant time
}
It swaps the front element with the back element, then pops it off. Of course, order is not retained.
The other problem is with your approach to memory management. Anytime you have explicit clean up code, you've done something wrong. It should be done automatically.
Use either Boost's ptr_vector, or a std::vector of smart pointers. (Note: do not use std::auto_ptr in a container, it's broken in this regard.) For a quick smart pointer suggestion, use either std::unique_ptr (if your compiler supports C++0x), or std::/boost::shared_ptr.
std::vector<Enemy*> enemies;
enemies.push_back(new Enemy());
This isn't exception-safe. If push_back fails to allocate enough memory to accommodate the new pointer, then the Enemy object is leaked.
Using a vector of smart pointers can solve this, but failing that you should reserve the space in the vector before pushing back:
std::vector<Enemy*> enemies;
enemies.reserve(1); // or more generally, enemies.reserve(enemies.size()+1);
enemies.push_back(new Enemy());
Now we know that push_back can't fail to allocate memory, and if reserve fails then the exception is thrown before the Enemy is created.
Certainly looks fine to me. You don't need the + 0 in the enemies.erase line, but aside from that, it's perfectly OK.
Yes, that's fine. You can simplify it a little:
delete enemies[0];
enemies.clear();
For removing the element, you could also use:
enemies.pop_back();
or (very similar to yours):
enemies.erase(enemies.begin());
Related
First of all, my motivation is to do efficient memory management on top of a C like computational kernel. And I tried to use the std::unique_ptr and std::vector, my code looks like below
// my data container
typedef std::unique_ptr<double> my_type;
std::vector<my_type> my_storage;
// when I need some memory for computation kernel
my_storage.push_back(my_type());
my_storage.back.reset(new double[some_length]);
// get pointer to do computational stuff
double *p_data=my_storage.back.get();
Notice here in practice p_data may be stored in some other container(e.g. map) to indexing each allocated array according to the domain problem, nevertheless, my main questions are
Here is std::vector a good choice? what about other container like std::list/set?
Is there fundamental problem with my allocation method?
Suppose after I use p_data for some operations, now I want to release the memory chunk pointed by the raw pointer p_data, what is the best practice here?
First of all, if you are allocating an array you need to use the specialization std::unique_ptr<T[]> or you won't get a delete [] on memory release but a simple delete.
std::vector is a good choice unless you have any explicit reason to use something different. For example, if you are going to move many elements inside the container then a std::list could perform better (less memmove operations to shift things around).
Regarding how to manage memory, it depends mainly on the pattern of utilization. If my_storage is mainly responsible for everything (which in your specification it is, since unique_ptr expresses ownership), it means that it will be the only one who can release memory. Which could be done simply by calling my_storage[i].reset().
Mind that storing raw pointers of managed objects inside other collections leads to dangling pointers if memory is released, for example:
using my_type = std::unique_ptr<double[]>;
using my_storage = std::vector<my_type>;
my_storage data;
data.push_back(my_type(new double[100]));
std::vector<double*> rawData;
rawData.push_back(data[0].get());
data.clear(); // delete [] is called on array and memory is released
*rawData[0] = 1.2; // accessing a dangling pointer -> bad
This could be a problem or not, if data is released by last then there are no problems, otherwise you could store const references to std::unique_ptr so that at least you'd be able to check if memory is still valid, e.g.:
using my_type = std::unique_ptr<double[]>;
using my_managed_type = std::reference_wrapper<const my_type>;
std::vector<my_managed_type> rawData;
Using std::unique_ptr with any STL container , including std::vector, is fine in general. But you are not using std::unique_ptr the correct way (you are not using the array specialized version of it), and you don't need to resort to using back.reset() at all. Try this instead:
// my data container
typedef std::unique_ptr<double[]> my_type;
// or: using my_type = std::unique_ptr<double[]>;
std::vector<my_type> my_storage;
my_type ptr(new double[some_length]);
my_storage.push_back(std::move(ptr));
// or: my_storage.push_back(my_type(new double[some_length]));
// or: my_storage.emplace_back(new double[some_length]);
I was wondering if it is OK to always use emplace to replace insert when inserting a single element into a STL container, like set, unordered_set?
From the signature, emplace is simpler and do not involve overloads. Is there any issue with stop using insert and use emplace all the time?
Note: there are SO questions asking about the difference between emplace and insert/push_back etc. (e.g. here, here, and here) I understand the difference, and it seems to me that emplace is better in every way. I just want to confirm if it's OK to deprecate insert.
There are some examples here that can be adapted to emplace and insert, showing when the behaviour may differ.
These examples may seem a bit artificial, so I'll give one that will hopefully appear less so:
#include <set>
template <typename T>
T id(T x) { return x; }
int main() {
std::set<int(*)(int)> s;
s.insert(id); // OK
s.emplace(id); // error
s.emplace(id<int>); // OK
}
insert can deduce the template parameter of id because it knows what type it wants. For emplace you get an error unless you explicitly specify.
Always? No, certainly not.
Consider the following example, which uses std::vector for simplicity (assume uptr is a smart pointer acting generally like std::unique_ptr):
std::vector<uptr<T>> vec;
vec.insert(vec.begin(), new T());
It is exception-safe. A temporary uptr is created to pass to insert, which is moved into the vector. If reallocation of the vector fails, the allocated T is owned by a smart pointer which correctly deletes it.
Compare to:
std::vector<std::uptr<T>> vec;
vec.emplace(vec.begin(), new T());
emplace is not allowed to create a temporary object. The uptr will be created once, in-place in the vector. If reallocation fails, there is no location for in-place creation, and no smart pointer will ever be initialized. The T will be leaked.
Of course, the best alternative is:
std::vector<std::unique_ptr<T>> vec;
vec.insert(vec.begin(), make_unique<T>());
which uses a standard smart pointer and makes the smart pointer creation explicit.
I'm not sure if I'm using the right terminology here, but say I have a function that returns a vector:
std::vector<int> func()
{
std::vector<int> vec(100,1);
return vec;
}
And when I call this function I want to allocate the vector on the heap. Can I do this?
I'm thinking something along the lines of this:
std::shared_ptr<std::vector<int>> vec(new std::vector<int>);
vec->swap(func());
Is there a way of doing this that is less convoluted, without changing func()?
Just try to remove that std::move, it's a specific compiler exception to avoid you put a std::move and let the compiler to do the rest.
std::vector<int> func()
{
std::vector<int> vec(100,1);
return vec; // NOT: return std::move(vec);
}
Why?
Because, the automatic object vec is going to destroy after executing return and it will be behave as same as a rvalue in this case. Then compiler will move it. Putting std::move will annoy the compiler to NRVO.
That simple returning the vector is optimized and don't worry about the performance.
The only better way i can think of is not use std::move since the compiler automatically does RVO
The second expression can be shortened a bit :
std::vector<int>* vec2 = new std::vector<int>( f() );
And just like what other says, allocating vector on the heap isn't really neccessary
I don't know what you're doing, how much can you optimize away from the stack without any trade-offs or from the heap if you want more fragments in your system memory ? If you have millions of records you need to allocate on "your heap", the first thing comes to my mind is your chance to get it corrupted with operations possible existing in your code is high. Second, heap size is limited then you need to re-implement your allocator to handle "how to deal with small memory and large data to be stored".
If you insist on optimization strategy over heap management, then returning pointer to the vector seems promising
std::vector<int*>* yourfunc()
{
// do something
return pVec;
}
then new method is applied but object deletion at the end is still required.
I want to know if there is a way to keep track of addresses of elements in a vector.
I like to use vector of solid elements like std::vector<MyObject> vec because:
std::vector do all the allocation / deallocation stuff for me
it also ensures me that my elements are stored in contiguous memory
I can get benefits of all code that work with vectors (e.g. <algorithm>)
This is exactly what I want. The problem arises when I want to store the address / reference of elements of my vector in other objects. In fact, the problem really arises when std::vector need to reallocate memory.
I tried to find alternatives to my problem:
Use vector of pointers / smart pointers : No, the pointers will be allocated contiguously but not the elements
Use vector of pointers / smart pointers and write my own operator new/new[] for MyObject : Humm, that seems better but no. By using a vector to allocate my elements I can say : "those particular set (I do not refer here to std::set) of elements must be allocated contiguously, not all". In fact I may want to have other set of elements that should be allocated contiguously because of the way I want to use them and using a vector to do that is exactly what (I think) I need. Thats also implies that I'm doing the job I want the vector to do.
Why not using boost multi-index? : In some ways that will do what I want because I want to store pointers/smartpointers of my vector elements in other containers. But no again because I really want to store reference/pointer/smartpointer of my vector's elements inside other objects, not just other containers.
What I would loved to have is a vector that can give me a pointer object that will allways point the the address of the desired element and I will use it like that :
std::vector<MyObject> vec;
// insert some elements
...
// get a pointer object by index or by using an iterator
// does something like that exist?
std::vector<MyObject>::pointer ptr = vec.get_pointer_at(5);
// do what I want on the vector except removing the element
...
// use my pointer whatever reallocations occurred or not
ptr->doSomething();
That sounds like an iterator that will never be invalidated except the fact I don't need/want to perform arithmetic on it (+x, -x, ++, --).
So, can someone leads me to the way to achieve what I want or explain me why/where I'm wrong wanting to do this? Please accept my apologize for my lack of knowledge in STL if there is a well known solution that I missed / or if this question has already be answered.
Edit:
I think that if I have to code such kind of pointer, that means that I'm wanting something useless or I'm wrong somewhere (unless someone should have already wrote a template for that) . So I'm more looking to a validated C++ idiom to get rid of this problem.
Although std::vector does not give you such pointer, there is no reason why you cannot make one yourself. All it takes is a class that keeps a reference to the std::vector object and the index, and overloads the prefix operator * and the infix operator -> (you need four overloads - const and non-const for each operator).
You would use this pointer like this:
std::vector<int> vect = {2, 4, 6, 8, 10, 12, 14, 16};
vect_ptr<int> ptr(vect, 5); // <<== You need to implement this
*ptr = 123;
cout << *ptr << endl;
The implementation of these overloads would grab the std::vector's begin() iterator, and return the result of calling vect.at(index). This would look like a pointer from the outside, but the object to which it points would change as the content of the std::vector gets resized.
As far as I know, there is nothing in the standard library nor in Boost to address your problem. A solution would be to implement your own kind of element pointer:
template<typename T>
class vector_element
{
public:
vector_element( std::vector<T>& v, std::size_t i )
: m_container( v ), m_element_index(i)
{ }
T& operator*() { return m_container[m_element_index]; }
T* operator->() { return &m_container[m_element_index]; }
private:
std::vector<T>& m_container;
std::size_t m_element_index;
};
I have a vector of vectors and I wish to delete myvec[i] from memory entirely, free up the room, and so on. Will .erase or .clear do the job for me? If not, what should I do?
Completely Removing The Vector
If you want to completely remove the vector at index i in your myvec, so that myvec[i] will no longer exist and myvec.size() will be one less that it was before, you should do this:
myvec.erase (myvec.begin() + i); // Note that this only works on vectors
This will completely deallocate all memories owned by myvec[i] and will move all the elements after it (myvec[i + 1], myvec[i + 2], etc.) one place back so that myvec will have one less vector in it.
Emptying But Keeping The Vector
However, if you don't want to remove the ith vector from myvec, and you just want to completely empty it while keeping the empty vector in place, there are several methods you can use.
Basic Method
One technique that is commonly used is to swap the vector you want to empty out with a new and completely empty vector, like this:
// suppose the type of your vectors is vector<int>
vector<int>().swap (myvec[i]);
This is guaranteed to free up all the memory in myvec[i], it's fast and it doesn't allocate any new heap memory or anything.
This is used because the method clear does not offer such a guarantee. If you clear the vector, it always does set its size to zero and destruct all the elements, but it might not (depending on the implementation) actually free the memory.
In C++11, you can do what you want with two function calls: (thanks for the helpful comment)
myvec[i].clear();
myvec[i].shrink_to_fit();
Generalization
You can write a small function that would work for most (probably all) STL containers and more:
template <typename T>
void Eviscerate (T & x)
{
T().swap (x);
}
which you use like this:
Eviscerate (myvec[i]);
This is obviously cleaner and more readable, not to mention more general.
In C++11, you can also use decltype to write a generic solution (independent of the type of your container and elements,) but it's very ugly and I only put it here for completeness:
// You should include <utility> for std::remove_reference
typename std::remove_reference<decltype(myvec[i])>::type().swap(myvec[i]);
My recommended method is the Eviscerate function above.
myvec.erase( myvec.begin() + i ) will remove myvec[i]
completely, calling its destructor, and freeing all of its
dynamically allocated memory. It will not reduce the memory
used directly by myvec: myvec.size() will be reduced by one,
but myvec.capacity() will be unchanged. To remove this last
residue, C++11 has myvec.shrink_to_fit(), which might remove
it; otherwise, you'll have to make a complete copy of myvec,
then swap it in:
void
shrink_to_fit( MyVecType& target )
{
MyVecType tmp( target.begin(), target.end() );
target.swap( tmp );
}
(This is basically what shring_to_fit will do under the hood.)
This is a very expensive operation, for very little real gain,
at least with regards to the removal of single elements; if you
are erasing a large number of elements, it might be worth
considering it after all of the erasures.
Finally, if you want to erase all of the elements,
myvec.clear() is exactly the same as myvec.erase() on each
element, with the same considerations described above. In this
case, creating an empty vector and swapping is a better
solution.