I have two vectors and for some elements (not all) i need them to be connected ~ if i delete/change this element in one vector it should be removed/changed in both.
Something similar like pointers:
int r = 10;
int *p= &r;
*p = 3;
For example in next code it should change myvector2[0].a to 7.
#include <iostream>
#include <vector>
using namespace std;
struct elt {
int a, b, c;
};
int main()
{
vector<elt> myvector;
vector <elt> myvector2;
elt elt1 = {1,3,3};
myvector.push_back(elt1);
elt *elt2 = &elt1;
myvector2.push_back(*elt2);
myvector[0].a=7;
cout << myvector[0].a << endl; //7
cout << myvector2[0].a << endl; //1
return 0;
}
How can i make this possible? Please help!!!
As tgmath explained, the issue is that you wind up with two different objects in your vectors, as the standard containers store elements by value. I would recommend that you use shared pointers to properly maintain the lifetime of the objects (note this uses C++11 features):
#include <iostream>
#include <vector>
#include <memory>
struct elt {
int a, b, c;
};
int main()
{
std::vector<std::shared_ptr<elt>> myvector;
std::vector<std::shared_ptr<elt>> myvector2;
auto elt1 = std::make_shared<elt>(elt {1,3,3});
myvector.push_back(elt1);
myvector2.push_back(elt1);
myvector[0]->a=7;
std::cout << myvector[0]->a << std::endl; //7
std::cout << myvector2[0]->a << std::endl; //7
return 0;
}
Pointers and references (and iterators) to elements of std::vector are invalidated whenever the vector reallocates, which can happen during insertion. So you can only keep these if the vector is guaranteed not to reallocate for the lifetime of the pointer/reference. This can be achieved if you don't insert into the vector, or if you call reserve() on it before you start (and before you acquire the pointer/reference/iterator), extending its capacity so that no reallocations will be necessary.
If you can't guarantee that, your only option is to keep the index instead of a pointer/reference. Of course, you will also need access to the vector itself for this to work, but you should be able to keep a pointer or reference to it, e.g.
typedef std::pair<std::vector<elt>*, size_t> ReferenceIntoVector;
myvector2.push_back(*elt2); adds a copy of *elt2 into myvector2
This means that both vector have their own copy of the elt object. And both of them are distinct from elt1.
If you change the one in the first vector, the second does not change at all.
For this purpose yiu would need a std::vector<elt*> to have different pointers to the same object in different vectors.
First, there is no built in way to automatically remove an element from one vector if you happen to delete it from another.
In my opinion there are two different challenges here:
How can I update an element pointed to by one list to be updated in another?
How can I remove an element from one list, and have that removed from the other?
The first question is already answered in the other posts: Use std::shared pointers instead of your native pointers. They are just as fast and will take care of all the memory management for you.
Please note: That this approach will only work as long as you are only changing the value of the element pointed to by the shared pointer, and not what the shared pointer is pointing to.
In other words/code:
std::vector<std::shared_ptr<elt>> vec1, vec2;
// Insert some elements
vec1.push_back( std::make_shared( elt{ 1, 2, 3} );
vec2.push_back( vec1.back() );
vec1[0]->x = 5; // OK, updated in both vectors.
vec1[0] = make_shared(elt {3,2,1}); // Error: vec1[0] is pointing to a new object.
The other challenge is much harder, how can you automatically delete an element from both vectors. The short answer is "You can't", the slightly longer is, you can but not directly.
Approach 1: Setting deleted elements to nullptr.
This approach is a bit dirty an not something I would recommend as it requires all code that use either vector to check whether an element is nullptr.
// Encapsulate the object inside a `std::unique_ptr`
std::vector< std::shared_ptr< std::unique_ptr< elt >>> vec1, vec2;
// Adding elements are done similarly as before
vec1.push_back( std::make_shared( std::make_unique( elt{ 1, 2, 3} )));
vec2.push_back( vec1.back() );
// Now to delete a element you would do as follows
vec1[0]->reset(nullptr); // Flag this element as deleted
vec1[0]->erase( vec1.begin() ); // Remove element from vec1
// Now let us assume we are iterating through the other vector at a later time:
for (auto it = vec2.begin(); it != vec2.end(); ++it ) { // Using iterators makes the code cleaner.
if ( **it == nullptr ) { // If the unique_ptr == nullptr
it = erase(it);
else {
etl & the_value = ***it; // Yes you need all three, one for the iterator, one for the shared_ptr and one for the unique_ptr...
}
}
As you can see this quickly gets hairy. But if that is all you need it can work.
Approach 2: (The better in my opinion) Is to use the Observer/Observed Design Pattern.
In order to implement this pattern you will need to exchange your vector for another class. Let us make a simple example:
// First, create an interface describing all operations you want to be
// informed about.
template<class T>
class SharedElementListObserver {
protected:
void elementDeleted( const shared_ptr<T> & elem ) = 0;
}
template<class T>
class SharedElementList : public SharedElementListObserver<T> {
std::vector<std::shared_ptr<T>> data;
std::unordered_set<SharedElementListObserver*> observers;
public:
void push_back( const T & elem ) { data.push_back( std::make_shared<T>( elem )); }
void push_back( std::shared_ptr &sptr ) { data.push_back( sptr ); }
shared_ptr<T> operator[] (int index) {
return data[index];
}
shared_ptr<const T> operator[] (int index ) const {
return std::static_pointer_cast<const T>( data[index] );
}
// This will cause all instances of elem in all lists
// linked either directly and indirectly to this
// to be removed.
void delete( int idx ) {
if (idx >= 0 && idx < data.size() ) {
shared_ptr<T> temp = data[idx];
data.erase( data.begin() + idx );
for (auto observer : observers) {
observer->elementDeleted(temp);
}
}
}
// Link another list to this one to listen to deletions.
void link( SharedElementListObserver* observer ) {
if (observer == this) return;
else if (observers.insert(observer).second) {
observer->observers.insert(this);
}
}
// Unlink previously linked observer.
void unlink(SharedElementListObserver* observer) {
observer->observers.erase(this);
this->observers.erase(observer);
}
protected:
void elementDeleted( shared_ptr<T> & elem ) {
for (int i = 0; i < data.size(); ) {
if (data[i] == elem)
delete(i); // Not infinite loop, because of test above.
else
i++;
}
}
// You also need to write an operator=, a copy-constructor and a destructor
// that ensures that there are no dead observers in the observers list.
};
Depending on your assumptions this class can be implemented in a number of different ways. Some probably simpler than what I just did.
Please let me know if there are any errors in the above code.
Related
Hello dear stackoverflow once again I'm here for help!
The idea: I'm implementing HashTable separate chaining based on sets
The problem: The destructor of set do not really work and I have no idea why
The code of set:
class set {
std::list<std::string>* bucket_array;
size_t bucket_array_size;
size_t set_size;
const double max_load_factor = 3.0;
public:
// Creates an empty set
set() :
bucket_array(new std::list<std::string>[4]),
bucket_array_size(4),
set_size(0)
{
}
};
the main problem is HERE:
set::~set(){
for (size_t i=0;i<=bucket_array->size();i++){
for(auto p = bucket_array[i].begin(); p != bucket_array[i].end(); ++p){
bucket_array[i].erase(p);
}
}
delete[] bucket_array;
}
From list::erase:
References and iterators to the erased elements are invalidated.
So when you write
for(auto p = bucket_array[i].begin(); p != bucket_array[i].end(); ++p){
bucket_array[i].erase(p);
you invalidate p and ++p is UB. You have to use the return value of erase:
for(auto p = bucket_array[i].begin();
p != bucket_array[i].end();
p = bucket_array[i].erase(p)) { }
or even simpler:
bucket_array[i].erase(bucket_array[i].begin(),
bucket_array[i].end());
But why do you erase all the lists manually? delete[] bucket_array; will do it automatically.
Even better would be to use std::vector and then even the delete becomes automatic and you wouldn't need set::~set() at all.
push_back, begin, end are described as concurrent safe in
https://learn.microsoft.com/en-us/cpp/parallel/concrt/reference/concurrent-vector-class?view=vs-2019#push_back
However the below code is asserting. Probably because element is added but not initialized yet.
struct MyData
{
explicit MyData()
{
memset(arr, 0xA5, sizeof arr);
}
std::uint8_t arr[1024];
};
struct MyVec
{
concurrency::concurrent_vector<MyData> v;
};
auto vector_pushback(MyVec &vec) -> void
{
vec.v.push_back(MyData{});
}
auto vector_loop(MyVec &vec) -> void
{
MyData myData;
for (auto it = vec.v.begin(); it != vec.v.end(); ++it)
{
auto res = memcmp(&(it->arr), &(myData.arr), sizeof myData.arr);
assert(res == 0);
}
}
int main()
{
auto vec = MyVec{};
auto th_vec = std::vector<std::thread>{};
for (int i = 0; i < 1000; ++i)
{
th_vec.emplace_back(vector_pushback, std::ref(vec));
th_vec.emplace_back(vector_loop, std::ref(vec));
}
for(auto &th : th_vec)
th.join();
return 0;
}
According to the docs, it should be safe to append to a concurrency::concurrent_vector while iterating over it because the elements are not actually stored contiguously in memory like std::vector:
A concurrent_vector object does not relocate its elements when you append to it or resize it. This enables existing pointers and iterators to remain valid during concurrent operations.
However, looking at the actual implementation of push_back in VS2017, I see the following, which I don't think is thread-safe:
iterator push_back( _Ty &&_Item )
{
size_type _K;
void *_Ptr = _Internal_push_back(sizeof(_Ty), _K);
new (_Ptr) _Ty( std::move(_Item));
return iterator(*this, _K, _Ptr);
}
I have to speculate on _Internal_push_back here, but I'd wager it allocates raw memory for storing the item (and points the last element towards this new node) so that the next line can use emplacement new. I'd imagine that _Internal_push_backis internally thread-safe, however I don't see any synchronization happening before the emplacement new. Meaning the following is possible:
memory is obtained and the node is "present" (yet emplacement new hasn't happend)
the looping thread encounters this node and performs memcmp to discover that they're not equal
emplacement new happens.
There's definitely a race condition here. I can spontaneously reproduce the problem, moreso the more threads I use.
I recommend that you open a ticket with Microsoft support on this one.
I want to have a function which iterates over a vector & picks and chooses an element which it then returns to the consumer in the form of a pointer, i.e. the pointer should point to the item in the vector. What I have so far is:
#include <vector>
class data_t {
public:
data_t(){mydat=99;}
~data_t(){}
int get_dat(){return mydat;}
private:
int mydat;
};
void *myfunc(std::vector<data_t> foo);
int main(void) {
std::vector<data_t> container;
data_t tmp;
data_t *res=nullptr;
container.push_back(tmp);
container.push_back(tmp);
res = (data_t*)myfunc(container);
res->get_dat();
}
void *myfunc(std::vector<data_t> foo) {
for (auto itr = foo.begin(); itr != foo.end(); itr++) {
if (itr->get_dat())
return &*itr;
}
return nullptr;
}
but I'm not sure about the return &*itr - as it doesn't seem ight to first dereference the iterator and then return the pointer o it. Plus even though itr is local, it does point to a globally available vector element.
How do I do this better?
You can do far better - currently the behaviour of your code is undefined since you pass foo by value and so a returned pointer will be invalidated as that value copy will go out of scope.
It would be far less idiosyncratic to pass the vector by (preferably) const reference, and either return a size_t (or, pedantically a std::vector<data_t>::size_type) type for the index of the element, or an iterator (your value of itr) to an element in the container.
There's nothing wrong with the &* notation when used appropriately. It crops up a fair bit when working with smart pointers and optional types.
This function signature screams "wrong" to me
void *myfunc(std::vector<data_t> foo);
You shouldn't be returning a void *, and you shouldn't be taking the vector by value.
using data_vec = std::vector<data_t>;
data_vec::iterator myfunc(data_vec & foo);
Now you don't have to cast in main, nor do you have to initialise with nullptr
int main(void)
{
data_vec container;
container.emplace_back();
container.emplace_back();
auto res = myfunc(container);
res->get_dat();
}
I have a vector of object pointers that I am adding to and deleting from while looping through to update objects. I can't seem to delete objects that have "died" from the vector without causing a memory error. I'm not really sure what I'm doing wrong. Listed below is my update method and it's sub method.
void Engine::update(string command){
if(getGameOver()==false){
for(p=objects.begin();p!=objects.end();p++){
spawnUpdate(command);
//cout<<"Spawn"<<endl;
objectUpdate(command);
//cout<<"object"<<endl;
scrollUpdate(command);
// cout<<"scroll"<<endl;
killUpdate(command);
//cout<<"kill"<<endl;
}
}
}
void Engine::killUpdate(std::string command){
if((*p)->getIsDead()==true){delete *p;}
}
void Engine::objectUpdate(string command){
(*p)->update(command,getNumObjects(),getObjects());
if(((*p)->getType() == PLAYER)&&((*p)->getPosX()>=getFinishLine())){setGameOver(true);}
}
void Engine::scrollUpdate(string command){
//Check player position relative to finishLine
if(((*p)->getType() == PLAYER)&&((*p)->getPosX()>(SCREEN_WIDTH/2))){
(*p)->setPosX((*p)->getPosX()-RUN_SPEED);
setFinishLine(getFinishLine()-RUN_SPEED);
for(q=objects.begin();q!=objects.end();q++){
//Shift objects to pan the screen
if((*q)->getType() == OPPONENT){(*q)->setPosX((*q)->getPosX()-RUN_SPEED);}
if((*q)->getType() == BLOCK){(*q)->setPosX((*q)->getPosX()-RUN_SPEED);}
}
}
}
void Engine::spawnUpdate(string command){
if(command.compare("shoot")==0){
cout<<"Bang!"<<endl;
if((*p)->getType() == PLAYER){objects.push_back(new Bullet((*p)->getPosX(),(*p)->getPosY(),(*p)->getState()));cout<<"Bullet success "<<endl;}
}
}
Some assumptions/definitions:
objects a member variable, something like vector<Object*> objects;
p is also a member variable, something like vector<Object*>::iterator p;
So p is an iterator, *p is an Object pointer, and **p is an Object.
The problem is that this method:
void Engine::killUpdate(std::string command) {
if ((*p)->getIsDead() == true) {
delete *p;
}
}
deallocates the Object pointed to by *p, the pointer in the vector at the position referenced by the p iterator. However the pointer *p itself is still in the vector, now it just points to memory that is no longer allocated. Next time you try to use this pointer, you will cause undefined behavior and very likely crash.
So you need to remove this pointer from your vector once you have deleted the object that it points to. This could be as simple as:
void Engine::killUpdate(std::string command) {
if ((*p)->getIsDead() == true) {
delete *p;
objects.erase(p);
}
}
However, you are calling killUpdate from update in a loop that iterates over the objects vector. If you use the code above, you will have another problem: once you erase p from the objects vector, it is no longer safe to execute p++ in your for-loop statement, because p is no longer a valid iterator.
Fortunately, STL provides a very nice way around this. vector::erase returns the next valid iterator after the one you erased! So you can have the killUpdate method update p instead of your for-loop statement, e.g.
void Engine::update(string command) {
if (getGameOver() == false) {
for (p = objects.begin(); p != objects.end(); /* NOTHING HERE */) {
// ...
killUpdate(command);
}
}
}
void Engine::killUpdate(std::string command) {
if ((*p)->getIsDead() == true) {
delete *p;
p = objects.erase(p);
} else {
p++;
}
}
This is of course assuming that you always call killUpdate in the loop, but I'm sure you can see the way around this if you don't -- just execute p++ at the end of the for-loop body in the case that you haven't called killUpdate.
Also note that this is not particularly efficient, since every time you erase an element of the vector, the elements that follow it have to be shifted back to fill in the empty space. So this will be slow if your objects vector is large. If you used a std::list instead (or if you are already using that), then this is not a problem, but lists have other drawbacks.
A secondary approach is to overwrite each pointer to a deleted object with nullptr and then use std::remove_if to remove them all in one go at the end of the loop. E.g.:
void Engine::update(string command) {
if (getGameOver() == false) {
for (p = objects.begin(); p != objects.end(); p++) {
// ...
killUpdate(command);
}
}
std::erase(std::remove_if(objects.begin(), objects.end(),
[](const Object* o) { return o == nullptr; }),
objects.end());
}
void Engine::killUpdate(std::string command) {
if ((*p)->getIsDead() == true) {
delete *p;
*p = nullptr;
}
}
The assumption this time is that you will never have a nullptr element of objects that you want to keep for some reason.
Since you seem to be a beginner, I should note that this:
std::erase(std::remove_if(objects.begin(), objects.end(),
[](const Object* o) { return o == nullptr; }),
objects.end());
is the erase-remove idiom, which is explained well on Wikipedia. It erases elements from the vector if they return true when a given function object is called on them. In this case, the function object is:
[](const Object* o) { return o == nullptr; }
Which is a lambda expression and is essentially shorthand for an instance of an object with this type:
class IsNull {
public:
bool operator() (const Object* o) const {
return o == nullptr;
}
};
One last caveat to the second approach, I just noticed that you have another loop over objects in scrollUpdate. If you choose the second approach, be sure to update this loop to check for nullptrs in objects and skip them.
Here is an issue (formatted for readability):
void Engine::update(string command)
{
if (getGameOver()==false)
{
for (p=objects.begin();p!=objects.end();p++)
{
spawnUpdate(command); // changes vector
//...
}
}
//...
}
void Engine::spawnUpdate(string command)
{
//...
objects.push_back(new Bullet((*p)->getPosX(),(*p)->getPosY(),(*p)->getState())); // no
//...
}
You have a loop with iterator p that points to elements in the object vector. When you call objects.push_back, the iterator for the vector may become invalidated. Thus that loop iterator p is no longer any good. Incrementing it in the for() will cause undefined behavior.
One way to get around this is to create a temporary vector that holds your updates. Then you add the updates at the end of your processing:
void Engine::update(string command)
{
std::vector<Object*> subVector;
if (getGameOver()==false)
{
for (p=objects.begin();p!=objects.end();p++)
{
spawnUpdate(command, subVector);
//...
}
}
// add elements to the vector
object.insert(object.end(), subVector.begin(), subVector.end());
}
void Engine::spawnUpdate(string command, std::vector<Object*>& subV)
{
if (command.compare("shoot")==0)
{
cout<<"Bang!"<<endl;
if ((*p)->getType() == PLAYER)
subV.push_back(new Bullet((*p)->getPosX(),(*p)->getPosY(),(*p)->getState()));
cout<<"Bullet success "<<endl;
}
}
You could avoid most of these issues by not using raw pointers. Clearly your code uses the semantic that the vector owns the pointers, so you can express this directly:
std::vector< std::unique_ptr<Object> > objects;
Then you may insert into the vector by using objects.emplace_back(arguments,to,Object,constructor); , and when you remove from the vector it will automatically delete the Object.
You still need to watch out for erase invalidating iterators, so keep using the erase-remove idiom as explained by Tyler McHenry. For example:
objects.erase( std::remove_if( begin(objects), end(objects),
[](auto&& o) { return o->getIsDead(); }), end(objects) );
Note - auto&& is permitted here since C++14; in C++11 you'd have to use std::unique_ptr<Object>&. Required includes are <algorithm> and <memory>.
And please stop using global iterators, keep p local to the function and pass any arguments you need to pass.
I'm trying to delete everything from a std::vector by using the following code
vector.erase( vector.begin(), vector.end() );
but it doesn't work.
Update: Doesn't clear destruct the elements held by the vector? I don't want that, as I'm still using the objects, I just want to empty the container
I think you should use std::vector::clear:
vec.clear();
EDIT:
Doesn't clear destruct the elements
held by the vector?
Yes it does. It calls the destructor of every element in the vector before returning the memory. That depends on what "elements" you are storing in the vector. In the following example, I am storing the objects them selves inside the vector:
class myclass
{
public:
~myclass()
{
}
...
};
std::vector<myclass> myvector;
...
myvector.clear(); // calling clear will do the following:
// 1) invoke the deconstrutor for every myclass
// 2) size == 0 (the vector contained the actual objects).
If you want to share objects between different containers for example, you could store pointers to them. In this case, when clear is called, only pointers memory is released, the actual objects are not touched:
std::vector<myclass*> myvector;
...
myvector.clear(); // calling clear will do:
// 1) ---------------
// 2) size == 0 (the vector contained "pointers" not the actual objects).
For the question in the comment, I think getVector() is defined like this:
std::vector<myclass> getVector();
Maybe you want to return a reference:
// vector.getVector().clear() clears m_vector in this case
std::vector<myclass>& getVector();
vector.clear() should work for you. In case you want to shrink the capacity of the vector along with clear then
std::vector<T>(v).swap(v);
vector.clear() is effectively the same as vector.erase( vector.begin(), vector.end() ).
If your problem is about calling delete for each pointer contained in your vector, try this:
#include <algorithm>
template< typename T >
struct delete_pointer_element
{
void operator()( T element ) const
{
delete element;
}
};
// ...
std::for_each( vector.begin(), vector.end(), delete_pointer_element<int*>() );
Edit: Code rendered obsolete by C++11 range-for.
Use v.clear() to empty the vector.
If your vector contains pointers, clear calls the destructor for the object but does not delete the memory referenced by the pointer.
vector<SomeClass*> v(0);
v.push_back( new SomeClass("one") );
v.clear(); //Memory leak where "one" instance of SomeClass is lost
Is v.clear() not working for some reason?
If you keep pointers in container and don't want to bother with manually destroying of them, then use boost shared_ptr. Here is sample for std::vector, but you can use it for any other STL container (set, map, queue, ...)
#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>
struct foo
{
foo( const int i_x ) : d_x( i_x )
{
std::cout << "foo::foo " << d_x << std::endl;
}
~foo()
{
std::cout << "foo::~foo " << d_x << std::endl;
}
int d_x;
};
typedef boost::shared_ptr< foo > smart_foo_t;
int main()
{
std::vector< smart_foo_t > foos;
for ( int i = 0; i < 10; ++i )
{
smart_foo_t f( new foo( i ) );
foos.push_back( f );
}
foos.clear();
return 0;
}
Adding to the above mentioned benefits of swap(). That clear() does not guarantee deallocation of memory. You can use swap() as follows:
std::vector<T>().swap(myvector);
If your vector look like this std::vector<MyClass*> vecType_pt you have to explicitly release memory ,Or if your vector look like : std::vector<MyClass> vecType_obj , constructor will be called by vector.Please execute example given below , and understand the difference :
class MyClass
{
public:
MyClass()
{
cout<<"MyClass"<<endl;
}
~MyClass()
{
cout<<"~MyClass"<<endl;
}
};
int main()
{
typedef std::vector<MyClass*> vecType_ptr;
typedef std::vector<MyClass> vecType_obj;
vecType_ptr myVec_ptr;
vecType_obj myVec_obj;
MyClass obj;
for(int i=0;i<5;i++)
{
MyClass *ptr=new MyClass();
myVec_ptr.push_back(ptr);
myVec_obj.push_back(obj);
}
cout<<"\n\n---------------------If pointer stored---------------------"<<endl;
myVec_ptr.erase (myVec_ptr.begin(),myVec_ptr.end());
cout<<"\n\n---------------------If object stored---------------------"<<endl;
myVec_obj.erase (myVec_obj.begin(),myVec_obj.end());
return 0;
}
class Class;
std::vector<Class*> vec = some_data;
for (unsigned int i=vec.size(); i>0;) {
--i;
delete vec[i];
vec.pop_back();
}
// Free memory, efficient for large sized vector
vec.shrink_to_fit();
Performance: theta(n)
If pure objects (not recommended for large data types, then just
vec.clear();