I wonder how to get access to element of list that contains pointers to objects. I want to achieve that without dereferencing. Propably it will be much easier if i just show what i want. So I have list:
list<ObjectClass*> nameOfObject;
and I have method:
bool collision(list<ObjectClass*>::iterator&);
And inside definition of that method I have:
{
if((*nameOfObject)->getSprite()) return true;
else return false;
}
What i want is to getSprite without needing to dereference nameOfObject inside method, so something like that:
{
if((nameOfObject)->getSprite()) return true;
else return false;
}
Everything that i tried is not working. I thought that it would be easy but i really don;t get it. Any ideas? I will add that list has to contain pointer to the objects, because of polimorphysm.
list<ObjectClass*>::iterator&
It's unclear why iterator is passed by reference.
*nameOfObject
This is ill-formed because std::list doesn't have indirection operator. I suspect that you may have shadowed that variable, and forgotten to include the shadowing variable in the example.
What i want is to getSprite without needing to dereference nameOfObject inside method,
Then you need to have an instance of a class with getSprite member function in the class rather than a pointer/iterator to such. If you do have a pointer/iterator, then there is no way to access the pointed object through the pointer without indirection.
so something like that:
(nameOfObject)->getSprite()
That does dereference nameOfObject. -> is the indirecting member access operator. It is also ill-formed with a list.
Any ideas?
Avoid wanting impossible things ¯\_(ツ)_/¯
You usually don't pass single iterator around.
If you want single object, pass single object (whether by reference or pointer)
I write an example code, hope it helps.
fIter is probably what most close to what you currently have
f is demonstrate you can iterate collection without directly use iterator
//
// https://stackoverflow.com/q/63156916/5980430
//
#include <list>
#include <iostream>
class ObjectClass{
public:
int spriteID;
int getSprite(){return spriteID;}
};
//your *collision* function
void collision(ObjectClass& obj){
std::cout << obj.getSprite() << '\n';
}
void f(std::list<ObjectClass>& objs){
for (auto& obj : objs){
collision(obj);
}
}
//even with iterator, you dereference it before pass in other functions
void fIter(std::list<ObjectClass>& objs){
for (auto it = objs.begin(); it != objs.end(); ++it){
collision(*it);
}
}
int main(){
std::list<ObjectClass> objects;
objects.push_back({1});
objects.push_back({2});
objects.push_back({3});
f(objects);
fIter(objects);
}
https://wandbox.org/permlink/SgI5ibjaIXd644DH
Related
Note: Apologies if the title is unclear, I don't quite know how to express the issue in proper terms (improvement suggestions are very welcome).
Code, onlinegdb example of the working version and example of the non-working one first to simplify the explanation:
#include <iostream>
#include <vector>
#include <memory>
class A {
public:
int v = 0;
};
void some_library_function(const std::vector<A*>& objects)
{
// do something to each object without taking ownership
for(auto p : objects)
{
p->v = 42;
}
}
class B
{
public:
std::vector<std::shared_ptr<A>> m_objects; // this is a private field in my actual code
B():m_objects{std::make_shared<A>()}{};
void use_library()
{
std::vector<A*> observer_vector(m_objects.size());
for(int i=0; i<m_objects.size(); i++)
{
observer_vector[i] = m_objects[i].get(); // fails here if I use unique_ptr
}
some_library_function(observer_vector);
}
};
int main()
{
B b;
b.use_library();
std::cout << b.m_objects[0]->v;
return 0;
}
I have a library function that operates on a series of objects of class A passed in via std::vector<A*>. These objects are stored in a field of class B that owns the objects. I would like to model the "owns" part via a vector of std::vector<unique_ptr<A>>, but this makes it impossible to pass the objects down to the library function.
using shared_ptrs works, but I'm worried this is not as expressive as the unique_ptrs with regards to object ownership.
Is there a way to use unique_ptrs in the vector and still be able to use the library function?
You're already doing the right thing. A raw pointer is a perfectly reasonable way to model something with unknown or lacking ownership. You're not storing the vector anywhere, so there is no confusion and no risk.
The only problem here really is that you've had to regenerate the entire vector, which seems like a bit of a waste. Ultimately, if you're set on a vector<unique_ptr<A>> at the source, and you're stuck with vector<A*> at the destination, then there's nothing you can do about that. If the vector is small it doesn't really matter though.
observer_vector[i] = m_objects[i].get(); // fails if with unique_ptr because of operator= being deleted
No, that should be valid. You're just assigning a raw pointer.
I though that I understood iterators and addressing etc. but obviously not. See my below code below which is purely an example.
I need to be able to pass by pointer or reference each structure of mystructs to MyFunc(). The function should be able to update the actual structure that is passed, and not by copy or value.
I receive the compiler error :
error: cannot convert 'MY_STRUCT' to 'MY_STRUCT*' for argument '1' to 'void MyFunc(MY_STRUCT*)'
If I just pass the iterator address, this also doesn't work.
What is the correct way to do this. Thanks in advance.
typedef struct
{
int var1;
int var2;
std::string name;
}MY_STRUCT;
std::list<MY_STRUCT> mystructs;
void MyFunc(MY_STRUCT*)
{
// Do something
}
// populate the list with structs etc.. not included here
//.....
for (std::list<MY_STRUCT>::iterator it = mystructs.begin();it != mystructs.end(); ++it)
{
MyFunc(*it);
}
Passing by reference in C++ is done with:
void MyFunc(MY_STRUCT&)
{
// Do something
}
So your call would be correct, what you currently want is to pass the pointer, which you can do with dereferencing the dereferenced iterator (by passing the address of the dereferenced object):
void MyFunc(MY_STRUCT*)
{
// Do something
}
// populate the list with structs etc.. not included here
//.....
int main() {
for (std::list<MY_STRUCT>::iterator it = mystructs.begin();it != mystructs.begin(); ++it)
{
MyFunc(&*it);
}
}
Your function requires a pointer, use & to get the address of something.
MyFunc(&*it);
*it returns a reference to the MY_STRUCT object, you need to use & to convert that reference to a pointer. This is normal, the fact that you are using iterators makes no difference at all.
The alternative (maybe better in C++) would be to convert your MyFunc function to take a reference instead of a pointer.
I'd like to store objects of a class in an std::map. Here is a working example showing how I am doing it currenty
#include <iostream>
#include <map>
class A
{
private:
int a;
std::string b;
public:
A(int init_a, std::string init_b) : a(init_a), b(init_b){};
void output_a() {std::cout << a << "\n";}
};
int main()
{
std::map<size_t, A> result_map;
for (size_t iter = 0; iter < 10; ++iter)
{
A a(iter, "bb");
result_map.insert(std::make_pair(iter, a));
}
return 0;
}
I have two question to this example:
Is this the professional C++-way to store objects in an std::map in the above case? Or should I create a pointer to an object of A and store that instead? I like the first (current) option as I don't have to worry about memory management myself by using new and delete - but most importantly I'd like to do things properly.
How would I go about calling a member function of, say, result_map[0]? I naively tried result_map[0].output_a(), but that gave me the error: error: no matching function for call to ‘A::A()’
Is this the professional C++-way to store objects in an std::map in the above case?
It is fine, simpler code could be:
result_map.emplace(iter, A(iter, "bb") );
you should use whatever you find more readable. By the way calling integer counter iter is not a way to write a readable code.
How would I go about calling a member function of, say, result_map[0]?
You better use std::map::find:
auto f = result_map.find( 0 );
if( f != result_map.end() ) f->output_a();
problem with operator[] in your case - it has to create and instance if object does not exist with that index but you do not have default ctor for A.
1- It depends: If your class can be copied and you're not worried about performance issues with copying objects into the map, then that's a good way to do it. However, if say your class held any immutable data (std::mutex for example) you'd have to use a pointer, as the copy constructor c++ automatically generates would be ill formed, so it merely wouldn't be able to copy the class
2- result_map.at(0).output_a() or result_map.at(0)->output_a() if you're using a map of pointers
So I am unsure why this wont work, ive tried some googling, i just cant find out what the problem is
void Player::Cmd(std::vector<std::string> &tokens)
{
std::string str = tokens[0];
std::map<std::string, void (Player::*)()>::iterator it = playerCommands.find(str);
Func fun;
if (it != playerCommands.end())
{
fun = it->second; //i tried it->second(); same issue
fun(); //error C2064: term does not evaluate to a
//function taking 0 arguments
}
else
{
std::cout << "What? \n";
}
}
git hub for the project
https://github.com/lordkuragari/TextRPG
Contrary to your belief, your map doesn't hold function pointers. So you cannot call the elements in the map.
Rather, your map contains pointers to member functions. Non-static member functions aren't functions and cannot be called; rather, they have to be invoked on an object. You can invoke a member function on an object given by a pointer p via a function pointer ptfm like this:
(p->*ptmf)();
In your case, presumably you want to use p = this and ptfm = fun, so it'd be:
(this->*fun)();
Or, without the local variable:
(this->*it->second)();
In C++17 you can also use std::invoke(it->second, this).
I will post my code then explain my query:
typedef std::shared_ptr<SEntity> Entity;
//Scene_Ids is an enum
static std::map<Scene_Ids, std::vector<Entity> > m_scene_entities;
std::shared_ptr<SEntity>& SEntityManager::getEntity(const std::string& entity_name)
{
int counter = 0;
for (auto iter = m_scene_entities.begin(); iter != m_scene_entities.end(); ++iter)
{
if (iter->second[counter]->getId() == entity_name)
return iter->second[counter];
counter++;
}
//What would I return if the entity couldn't be found?
}
The code basically explains it all. I have a method in which if an "entity" is found in the std::vector inside of the map, it will return a reference to the std::shared_ptr type that it is. However, since I'm not returning a pointer, I cannot return nullptr. What could I return in a failure case.
Also, I know that std::shared_ptr is meant for having copies in several different places. For this, do I really need to return a reference or can I just return it by value?
Thanks!
Return the iterator rather than the contents of the iterator. That way you can tell whether you reached the end.
If it is expected that under normal circumstances getEntity will never fail to find the entity, then you should throw an exception.
If you would expect to fail to find some entites, then you can return a default-constructed shared_ptr <SEntity>. Be sure to check for that on the other end.
Remove the return by reference then return an empty shared pointer:
std::shared_ptr<SEntity> SEntityManager::getEntity(const std::string& entity_name) {
for { ... }
return Entity();
}
There's not really a good reason to return the shared pointer by reference. And the shared pointer has a default constructor that's basically the equivalent of nullptr. You can check it in the parent function by testing it as a bool. E.g.:
auto val = getEntity(...);
if (!val) { /* nothing found */ }
I suspect that you need to split tasks. For any normal operation (changing the values of SEntity parameters) you will just need to either return default constructed std::shared_ptr or found entity. No reference needed.
For *replacing the actual contents of shared_ptr* you can have a function like
void SEntityManager::replaceEntity(const std::string& entity_name, Entity* newEntity)
and replace the Entity if its found inside the function.
However, your code still is weird - what if, for example, there are multiple entity_name containing Entities in your vectors ?