I want to store the currently selected object (selected by mouse click) and then implement methods on this object. The currently selected object is chosen from an array:
for(int i=0; i<trackList.size(); i++)
{
trackList[i].setSelected(false);
if((trackList[i].isClicked(x,y)) && (!trackList[i].isSelected()))
{
trackList[i].setSelected(true);
currentSelected = trackList[i];
}
}
I am new to C++ and have read up on pointers etc. but I am struggling to understand where and how they should be used. Do I need to have my currentSelected object as a pointer to whatever trackList[i] is?
Can I then implement methods on this object using the pointer reference?
Many thanks
EDIT:
trackList is storing a vector of Track objects:
std::vector<interface1::Track> trackList;
And currentSelected is storing a Track object which I want to apply methods to:
interface1::Track* currentSelected;
You need to do:
currentSelected = &(trackList[i]);
In order to assign the pointer the value of the address of trackList[i].
Another way is to use iterators, like this:
std::vector<interface1::Track> trackList;
std::vector<interface1::Track>::iterator it, currentSelected;
for (it = trackList.begin(); it != trackList.end(); it++)
{
it->setSelected(false);
if((it->isClicked(x,y)) && (!it->isSelected()))
{
it->setSelected(true);
currentSelected = it;
}
}
Later you can use currentSelected->setSelected(false); for both the pointer and iterator.
Related
So, I have an array of a class called "Customer"
Customer** customersarray[] = new Customer*[customer];
I'm receiving int customer with cin.
anyways, in customer.cpp, there is a method called void deactivate().
which goes like this:
void Custmoer::deactivate()
{
if (this != NULL)
remove this;
//this = NULL; I want to do this but it doesn't work.
}
and the purpose of this is to remove it from customer array when satisfies a certain condition. So for example,
for (int i = customer - 1; i >= 0; i--)
{
if (customersarray[i]->getAngerLevel() == 5) {
customersarray[i]->deactivate();
}
for (int z = i; i < customer - 1; i++) {
*(customersarray + z) = *(customersarray + z + 1);
}
customer--;
}
so my first questions are:
why does this = NULL not work?
is there a simpler way to remove something from pointer array when a condition is satisfied? (for example, remove all customers that has anger level of 5.)
Your mistake is thinking that you can remove something from a Customer* array by some magic inside the Customer class, but that's not true. Just remove a customer from the customer array where ever the customer array is. For instance using remove_if
#include <algorithm>
Customer** customersarray = new Customer*[customer];
...
customer = std::remove_if(customersarray, customersarray + customer,
[](Customer* c) { return c->anger() == 5; }) - customersarray;
This updates the customer variable to be the new size of the array, but doesn't free or reallocate any memory. Since you are using dynamic arrays and pointers you are responsible for that.
Which is why you should really not be using pointers or arrays, but using vectors instead.
std::vector<Customer> customerVector;
Life will be so much simpler.
Type of "this" is a constant pointer which means you cant change where it points
Your function can return a boolean and if its true just set your pointer to null
You'll be much better off using a std::vector, all memory memory management gets much safer. You cannot modify the this pointer, but that would be meaningless anyway:
It is a local variable, so any other pointer outside would not be changed, not even the one you called the function on (x->f(): the value of x is copied into this).
It contains the address of the current object - the current object is at a specific memory location and cannot be moved away from (not to be mixed up with 'moving' in the context of move semantics!).
You can, however, delete the current object (but I don't say you should!!!):
class Customer
{
static std::vector<Customer*> customers;
public:
void commitSuicide()
{
auto i = customers.find(this);
if(i != customers.end())
customers.erase(i);
delete this;
}
}
Might look strange, but is legal. But it is dangerous as well. You need to be absolutely sure that you do not use the this pointer or any other poiner to the current object any more afterwards (accessing non-static members, calling non-static functions, etc), it would be undefined behaviour!
x->commitSuicide();
x->someFunction(); // invalid, undefined behaviour!!! (x is not alive any more)
Similar scenario:
class Customer
{
static std::vector<std::unique_ptr<Customer>> customers;
public:
void commitSuicide()
{
auto i = customers.find(this);
if(i != customers.end())
{
customers.erase(i); // even now, this is deleted!!! (smart pointer!)
this->someFunction(); // UNDEFINED BEHAVIOUR!
}
}
}
If handling it correctly, it works, sure. Your scenario might allow a much safer pattern, though:
class Customer
{
static std::vector<std::unique_ptr<Customer>> customers;
public:
Customer()
{
customers->push_back(this);
};
~Customer()
{
auto i = customers.find(this);
if(i != customers.end())
customers.erase(i);
}
}
There are numerous variations possible (some including smart pointers); which one is most appropriate depends on the use case, though...
First of all, attending to RAII idiom, you are trying to delete an object before using its destructor ~Customer(). You should try to improve the design of your Customer class through a smart use of constructor and destructor:
Customer() {// initialize resources}
~Customer() {// 'delete' resources previously created with 'new'}
void deactivate() {// other internal operations to be done before removing a customer}
Then, your constructor Customer() would initialize your internal class members and the destructor ~Customer() would release them if necessary, avoiding memory leaks.
The other question is, why do you not use another type of Standard Container as std::list<Customer>? It supports constant time removal of elements at any position:
std::list<Customer> customers
...
customers.remove_if([](Customer foo) { return foo.getAngerLevel() == 5; });
If you only expect to erase Customer instances once during the lifetime of the program the idea of using a std::vector<Customer> is also correct.
I added also void Clear()-method.
https://redstoner.com/forums/threads/840-minimal-class-to-replace-std-vector-in-c-for-arduino
https://forum.arduino.cc/index.php?topic=45626.0
I'm asking about this Vector class.
void push_back(Data const &x) {
if (d_capacity == d_size) resize();
d_data[d_size++] = x;
}; // Adds new value. If needed, allocates more space
How to add "insert"-method to this Vector class (arduino use C++ but not have a standard vector methods)?
Vector<Sensor*> sensors;
I have a another class Sensor and I use vector like this.
push.back(new Sensor (1,1,"Sensor_1",2));
Is it possible to add values one by one to this vector class? And how to do it?
I like to ask also other question.
How can I call delete/call destructor for this Vector "sensors" so all pointers are deleted? Or sensors vector is deleted? I want to clear the data and then add data to it.
If you want to add an item to the end of the vector, use the push_back method you've quoted above. If you want to add an item somewhere else in the vector, you'll need to add your own method which re-sizes if necessary, shifts the elements above the insert location up one place and then copies the new element into the correct slot. Something like this (untested):
void insert_at(size_t idx, Data const &data) {
assert(idx < d_size);
if (d_capacity == d_size) {
resize();
}
for (size_t i = d_size; i > idx; --i) {
d_data[i] = std::move(d_data[i - 1]);
}
d_data[idx] = data;
++d_size;
}
As Nacho points out, you might be better off with a linked list if you're going to do a lot of these insert operations, especially if the data you're storing is large and/or has a complex move operator.
So I'm writing an API in C++ to be used in another GUI application I'll be writing. The API will allow the user to create instances of "MyObject" and modify the properties of that object, but the object itself will not be exposed to the client, only an ID to that object. So for instance:
Object_ID identifier = myApiCreateObject();
myApiModifyProperty(identifier, "PROPERTY_NAME", "value");
So the identifier acts as an external handler to a specific MyObject instance.
As of right now the Object_ID is defined as follows:
typedef int Object_ID;
Currently all MyObject instances are stored in an std::vector within my API. The Object_ID is simply the index in the vector that the desired instance lives.
The problem with this approach is that I don't know how to handle deleting instances of MyObject from the vector. For instance, let's say I have 10 instances of MyObject created and I want to delete the instance at index 5, I would want to do something like the following:
myApiDeleteObject(handlerForIndex5);
By doing this though, internally my API would remove that object from the std::vector and then would have to shift over all the objects at indices > 5. This would cause my external handlers to no longer reference the correct object.
So just using the index of the array by itself is not sufficient, but I don't know of a better alternative without having to expose the MyObject class to the client.
EDIT
Here's an updated example highlighting the issue at hand:
Internally the API performs certain algorithms on the list of objects, some of these algorithms require sorting the vector as a step.
So my GUI would do something like :
myApiBeginCalculations();
and then internally the API would be doing something like this:
myApiBeginCalculations()
{
//Start algorithm
.......
Sort(vector);
//Continue with algorithm
}
Then let's say after that algorithm is complete, the user wants to modify a given MyObject instance and start again:
myApiBeginCalculations();
myApiModifyProperty(myHandler, "PROPERTY", "VALUE");
myApiBeginCalculations();
myApiDeleteObject(myHandler);
myAPiBeginCalculations();
Internally myApi will be doing a bunch of things to the MyObject instances and I need a reliable way to keep track of individual instances on the client even as they get shuffled around.
You can use std::map in place of std::vector. So you can do look up quickly and remove objects whenever you need.
std::map<int, Object> Object_directory
You need to use an ID based on something that is both unique for each object and which remains constant for each object. Clearly an index into a vector you're continually rearranging does not qualify.
You haven't described the properties of the objects so I can't say whether there's something already suitable for this use, but if not then you can add something. You can assign an IDs to each object as you create them, or you could allocate the objects on the heap so that their addresses remain consistent as you, for example, sort a vector<unique_ptr<MyObject>>.
You'll have to consider each operation you need to perform and figure out the necessary performance. For example a linear search through the vector in order to find an object with a matching ID may be too slow for some purpose. In that case you'll have to figure out how to avoid that linear search, perhaps by keeping a map on the side or something, at the cost of having to keep the map updated during other operations.
I would suggest not generating an ID number at all. Simply use a real pointer to the actual Object instance instead. To hide it from the client, you can use void* or uintptr_t, and just have your API functions type-cast that value to an Object* pointer when needed. You can still keep track of the Object instances in a std::vector so you can perform your algorithms on the objects, but the order of the std:vector will not be important to clients, and deleting any given Object will not invalidate other object IDs.
typedef uintptr_t Object_ID;
typedef std::vector<Object*> ObjectVector;
typedef ObjectVector::iterator ObjectVectorIter;
ObjectVector objVec;
Object_ID myApiCreateObject()
{
try
{
std::auto_ptr<Object> obj(new Object);
objVec.push_back(obj.get());
return reinterpret_cast<Object_ID>(obj.release());
}
catch (const std::exception&)
{
return 0;
}
}
ObjectVectorIter myApiFindObject(Object_ID identifier)
{
Object *obj = reinterpret_cast<Object*>(identifier);
return std::find(objVec.begin(), objVec.end(), obj);
}
void myApiModifyProperty(Object_ID identifier, const char* propName, const char* propValue)
{
ObjectVectorIter iter = myApiFindObject(identifier);
if (iter != objVec.end())
iter->property[propName] = propValue;
}
void myApiDeleteObject(Object_ID identifier)
{
ObjectVectorIter iter = myApiFindObject(identifer);
if (iter != objVec.end())
{
Object* obj = *iter;
objVec.erase(iter);
delete obj;
}
}
Or, if you are using C++11:
typedef uintptr_t Object_ID;
typedef std::shared_ptr<Object> ObjectPtr;
typedef std::vector<ObjectPtr> ObjectVector;
typedef ObjectVector::iterator ObjectVectorIter;
ObjectVector objVec;
Object_ID myApiCreateObject()
{
try
{
ObjectPtr obj = std::make_shared<Object>();
objVec.push_back(obj);
return reinterpret_cast<Object_ID>(obj.get());
}
catch (const std::exception&)
{
return 0;
}
}
ObjectVectorIter myApiFindObject(Object_ID identifier)
{
Object *obj = reinterpret_cast<Object*>(identifier);
return std::find_if(objVec.begin(), objVec.end(), [obj](const ObjectPtr &p){ return p.get() == obj; });
}
void myApiModifyProperty(Object_ID identifier, const char* propName, const char* propValue)
{
ObjectVectorIter iter = myApiFindObject(identifier);
if (iter != objVec.end())
(*iter)->property[propName] = propValue;
}
void myApiDeleteObject(Object_ID identifier)
{
ObjectVectorIter iter = myApiFindObject(identifier);
if (iter != vec.end())
objVec.erase(iter);
}
I have the following piece of code in my entityManager.
void GameObjectManager::updateAll(float frametime)
{
checkAlive();
// iterate through the entityManager, updating each entity and then adding it into the quadTree.
for (auto itr = _gameObjects.begin(); itr != _gameObjects.end(); itr++)
{
itr->second->Update(frametime);
tree->AddObject(itr->second);
}
// iterate once again through the entityManager but this time checking itself against the quadTree.
for (auto x = _gameObjects.begin(); x != _gameObjects.end(); x++)
{
std::vector<std::unique_ptr<Entity>> returnObjects = tree->GetObjectsAt(x->second->GetPosition().x, x->second->GetPosition().y );
for ( int n = 0; n < (int)returnObjects.size(); n++ )
{
std::unique_ptr<Entity>& collided = returnObjects[n];
if(object->getEntityName() != collided->getEntityName())
{
if(object->GetBoundingRect().intersects(collided->GetBoundingRect()))
{
object->Touch(collided);
}
}
}
}
tree->Clear();
}
What would be the correct use of smart pointers in this example? When I add the entity to the quad tree should I create a shared_ptr, pass it over as a reference or use std::move? I'm leaning towards one of the first two as moving ownership of the pointer would move it from the std::map and this is something I don't want to be doing.
Are there simple rules I should follow as to when passing information? When should I be using references and when should I be using a shared_ptr?
When ownership semantics are employed I use the following basic approach to references.
Taking references by function parameter. The function is going to use this object but not going to store a reference to it beyond the lifetime of the function. Once the function has returned you are safe to destroy the object without worrying about dangling references or pointers.
Returning references. You are free to use the object but do not own it and cannot store a reference to it beyond the lifetime of the object returning the reference.
Changing the quadTree to accept and return references instead of strong pointers would seem to violate these two rules. That's OK but requires an additional change. In your case quadTree is a member variable. If an exception occurs quadTree will still contain references to objects it does not own and may no longer exist. This can be easily rectified by using a quadTree local to the scope of the calling function. This will guarantee that the lifetime of quadTree is not longer than _gameObjects - the actual owner.
This simply expands the first rule to include the lifetime of the object the function belongs to. The changes might look something like this (using pointers rather than references which can be applied just the same).
void GameObjectManager::updateAll(float frametime)
{
checkAlive();
quadTree tree;
// iterate through the entityManager, updating each entity and then adding it into the quadTree.
for (auto itr = _gameObjects.begin(); itr != _gameObjects.end(); itr++)
{
itr->second->Update(frametime);
tree.AddObject(itr->second.get());
}
// iterate once again through the entityManager but this time checking itself against the quadTree.
for (auto x = _gameObjects.begin(); x != _gameObjects.end(); x++)
{
std::vector<Entity*> returnObjects = tree->GetObjectsAt(x->second->GetPosition().x, x->second->GetPosition().y );
for ( int n = 0; n < (int)returnObjects.size(); n++ )
{
Entity* collided = returnObjects[n];
if(object->getEntityName() != collided->getEntityName())
{
if(object->GetBoundingRect().intersects(collided->GetBoundingRect()))
{
object->Touch(collided);
}
}
}
}
//tree.Clear(); // Called by destructor.
}
This question already has answers here:
How to delete an element from a vector while looping over it?
(6 answers)
Closed 9 years ago.
I use a vector of shared pointers to contain some game characters called customer.
typedef std::shared_ptr<Customer> customer;
std::vector<customer> customers;
customers.push_back(customer(new Customer()));
for(int i = 0; i < customers.size(); i++)
{
if(customers[i]->hasLeftScreen())
{
if(!customers[i]->itemRecieved())
outOfStocks++;
// Kill Character Here
}
}
I have used vectors to hold objects before so am used to calling erase on the vector and passing in the iterator. My question is there a way of deleting a the pointer from the vector in the above code snippet? I was hoping not to use an iterator here to simplify the code. I also need to delete the pointer because I was the customer to be removed from the game once it has left the screen.
Many thanks
Consider using an iterator, which frankly will be much easier to deal with. I'm not sure of your aversion to them, but see below:
std::vector<customer>::iterator it = customers.begin();
while (it != customers.end())
{
if(it->hasLeftScreen())
{
if(!it->itemRecieved())
outOfStocks++;
it = customers.erase(it);
continue;
}
++it;
}
This will remove the shared pointer instance from the vector. If the instance is the last reference to the shared pointer it will also release the associated memory of said Customer, firing its destructor, etc... (somewhat the point of using smart shared pointers in the first place, and props for using smart pointers, by the way).
You should always use iterators; it's a C++ idiom. This would change the code to...
for(auto i = customers.begin(); i != customers.end(); ++i)
{
if((*i)->hasLeftScreen())
{
if(!(*i)->itemRecieved())
outOfStocks++;
// Kill Character Here
}
}
Now, it is clear, we use the erase-remove idiom instead.
int outOfStocks = 0;
auto it = std::remove_if(customer.begin(), customers.end(), [&](Customer const& i) {
if(i->hasLeftScreen()) {
if(!i->itemRecieved()) {
outOfStocks++;
}
return true;
}
return false;
}
std::erase(it, customers.end());
You can also take advantage of "iterator arithmetic":
// Kill Character Here
customers.erase(customers.begin() + i);
... but that has a problem that customers.size() and the current index will get invalidated as the container will shrink.
Also, you don't need to explicitly delete the customer you're removing, because the smart pointer will take care of that.