Store pointers to an object in map - c++

I have a vector pointer that points to a vector<object> so
const std::vector<object> vecPtr* = &vec;
Now i'd like to fill in this manner std::multimap<std::string, object*> dataMap; where the key is object.name and value is pointer to an object.
I tried
for(std::vector<object>::const_iterator it = data->cbegin(); it != data->cend(); ++it){
dataMap.insert(std::pair<std::string, object*>(it->name, &it));
}
but i get an error.
error: no matching function for call to 'std::pair<std::basic_string<char>, object*>::pair(const string&, std::vector<object>::const_iterator*)'
dataMap.insert(std::pair<std::string, object*>(it->name, &it));
^
What am i doing wrong?
I know i complicating my life with pointers, but I want to avoid copying objects

In order to avoid copying objects consider to use reference of objects. Moreover, consider to use shared pointer such as std::shared_ptr (for C++11), or boost::shared_ptr. A good style is to avoid allocating memory manually. Let's do it in an automatic way provided by the STL.
class Object{};
typedef boost::shared_ptr < Object > ObjectPtr;
then
std::multimap < std::string, ObjectPtr > map;
Creating instances of Object just use:
ObjectPtr obj = boost::make_shared < Object > ();

&it is a pointer to iterator, not to an object. If you want to get a pointer to an object, write &*it.
After that you'll see an error saying that you can't convert from const object* to object* - this is because you are using const_iterator. So, depending on what you need, you can do two things.
Either declare dataMap as std::multimap<std::string, const object*> dataMap;, if you are not planning to change the objects in it.
Or use iterator:
for (std::vector<object>::iterator it = data->begin(); it != data->end(); ++it) {
dataMap.insert(std::pair<std::string, object*>(it->name, &*it));
}
By the way, this loop can be rewritten as:
for (auto& a : *data) {
dataMap.insert({a.name, &a});
}

Related

c++ references to heap objects?

I have the below bit of code:
map<int,int>& myMap = new map<int,int>();
but I get the following compiler error:
no suitable constructor exists to convert from "std::map<int,int, std::less<int>, std::allocator<std::pair<const int, int>>>*" to "std::map<int,int, std::less<int>, std::allocator<std::pair<const int, int>>>".
Does this mean I have to do:
map<int,int>& myMap = *new map<int,int>();
I thought that objects could passed to references without dereferencing first (as opposed to pointers)? Also I know smart pointers exist but I'm not trying to use those for now.
You can use
map<int,int>& myMap = *new map<int,int>();
but I don't recommend it.
The dynamically allocated memory has to be deallocated. At that time, you will need to use something along the lines of
delete &myMap;
That is poor quality code, IMO.
Use a smart pointer if you need dynamically allocated memory.
std::shared_ptr<map<int,int>> ptr = new map<int,int>();
If you need to use a reference, you can use:
map<int,int>& myMap = *ptr;
It will better if you can avoid dynamically allocated object altogether and use an automatic object (object in stack memory).
map<int,int> myMap;
Update, in response to OP's comment
In a comment you said
Yeah i want to keep that reference because im passing it to a recursive function
The C++ way to deal with it is to pass an object by reference.
void recursive_foo(std::map<int, int>& myMap)
{
}
void foo_user()
{
std::map<int, int> myMap;
// Fill up myMap
// ...
recursive_foo(myMap);
}
If the recursive function does not modify the object, you can follow the idiom used by the standard library and use iterators instead.
void recursive_foo(std::map<int, int>::iterator start,
std::map<int, int>::iterator end)
{
}
void foo_user()
{
std::map<int, int> myMap;
// Fill up myMap
// ...
recursive_foo(myMap.begin(), myMap.end());
}
I thought that objects could passed to references without dereferencing first (as opposed to pointers)?
Yes objects can be passed, but what you have here:
map<int,int>& myMap = new map<int,int>();
is not an object but reference which you try to initialize by pointer to dynamically allocated object. Just create object:
map<int,int> myMap;
and it should work fine.
To make things clear, you mixed different concepts, lets say we have a function that accepts variable of sometype by reference:
void func( sometype &ref ) { ... }
it does not mean you have to declare variable as reference to pass it there, you can pass automatic object:
sometype auto_object;
func( auto_object );
or pass dynamically allocated one:
sometype *ptr_to_object = new sometype;
func( *ptr_to_object );
delete ptr_to_object; // or better use smart pointer
and if you do not need this object to outlive scope where you use it it is preferable to use first variant.

Proper way to destroy a map that has pointer values

I am using std::map to map string values to MyType *. My map declaration looks like this:
map<string, MyType *> *my_map = new map<string, MyType>;
my_map is a private member variable of one of my classes. My problem is that I am unsure of how to destroy the map. When deleteing the map, I would also like to call delete on all of the MyType * contained in the map. Here is my current destructor:
my_map->erase(my_map->begin(), my_map->end());
delete my_map;
Will this delete the pointers contained in the map, or do I need to iterate through the map to delete each pointer before calling erase?
Pointers merely point. When using raw pointers, you need to know which part of your app owns the resources that the pointers point to. If they are owned by the map, you will need to iterate over the map and call delete on each pointer before the map is destroyed. But if the map just holds pointers to objects that are owned by other parts of your code, you don't need to do anything.
A safer solution is to use shared_ptr to manage object lifetime, which will ensure that the object gets deleted properly when the last shared_ptr is destroyed. You can store shared_ptrs inside the map and if no other shared_ptr instances reference the objects within the map, the objects will be destroyed when the map is destroyed, as desired.
If you use smart pointers instead of raw pointers, everything will be cleaned up for you automatically.
// header:
using MapType = std::map<std::string, std::shared_ptr<MyType>>;
shared_ptr<MapType> my_map;
// usage:
my_map.emplace("foo", std::make_shared<MyType>());
// destructor:
MyClass::~MyClass()
{
// nothing!
}
Will this delete the pointers contained in the map [...]?
No, given the code you have provided, you will leak every member of the map.
As a rule, for every new there must be a matching delete. You have a delete for the map, but none for the elements within.
The most correct solution to this problem is to not use dynamic allocation at all. Just store MyTypes directory, if possible:
map<string, MyType>
... and instead of dynamically allocating the map itself, store that automatically:
map<string,MyType> my_map;
If automatic storage duration is not possible for some reason, then use a smart pointer for the dynamic allocations. Given a C++11 compiler, use unique_ptr (or, rarely, shared_ptr or even weak_ptr) for the elements in the map:
map<string, unique_ptr<MyType>> my_map;
(Given a C++03 compiler, use the Boost equivalents thereof.) Then when my_map is destroyed, all the elements will be deleted.
Baring all of this, if you are in a situation where none of the above will work for you (I would by highly suspect), then you will need to iterate the map youself:
struct deleter
{
template <typename T> operator() (const T& rhs) const
{
delete rhs.second;
}
};
for_each (my_map->begin(), my_map->end(), deleter());
In C++11, this could be made a lambda, something along the line of:
for_each (my_map->begin(), my_map->end(), [](auto item) -> void
{
delete item.second;
});
In modern C++, just make your life easier and use pointers only if strictly required.
You started with this code:
map<string, MyType *> *my_map = new map<string, MyType>;
The first thing you can do is to consider using a std::map instance as data member, instead of a pointer to it.
Then, if MyType is not super-expensive to copy and its instances are only owned by the map, just consider a simple map from string to MyType (instead of MyType*):
// my_map data member - no pointers --> automatically deleted in class destructor
map<string, MyType> my_map;
If you really need a map containing pointers, consider using smart pointers, like std::shared_ptr (available in C++11/14) for shared ownership, or std::unique_ptr for unique non-shared ownership.
(If you target C++98/03, an option is to use boost::shared_ptr. Since there is no move semantics, you can't have unique_ptr, which is heavily based on the move semantics feature.)
e.g.:
// Map containing _smart_ pointers
// --> default destructor is fine (no need for custom delete code)
map<string, shared_ptr<MyType>> my_map;
As you can see, using value semantics (instead of raw pointers), or smart pointers, you can simplify your code and use the automatic destruction provided by C++.

How to insert an rvalue into map after calling a function on it

I'm trying to use a std::unordered_map<std::string, std::shared_ptr<CObject>> (hereby referred to as map) to be able to use the map for calling the same functions on different objects based on their name. Function pointers within the map would be one way to do it, but I thought it'd be cleaner to save the objects themselves in the map.
Now, the objects are stored in a shared_ptr, since they have dependencies from other usages (member functions automatically called before function calls, etc), and the shared_ptr are allocated using a function that wraps make_shared, which among other thing resets it, as well as catches and throws exceptions with added relevant information (probably not needed anymore, but it's a rather large code base, and it's a part of the coding standard). This function allocates the given objects by taking the shared_ptr as a reference, and returns void.
What I wanted to do was create a map with keys mapping to objects, and call the allocate function on all those objects. But since the allocate function does not return an OutputIterator or anything like it, I'm unable to use an std::inserter.
They way I don't want to do it is using lvalues, like:
std::map<std::string, std::shared_ptr<CObject>> objectMap;
shared_ptr< CObject> object;
allocate< CObject>( object );
objectMap.insert( make_pair("FirstObject", object ) );
The only way I've come up with is to call the allocate function on non-existing values on the map, as map would automatically create the objects for me if they don't exist. Like:
std::map<std::string, std::shared_ptr<CObject>> objectMap;
allocate< CObject>( objectMap["FirstObject"] );
Any other ideas?
You could use a function object like this to create the map elements:
struct AllocCObject {
std::pair<const std::string, std::shared_ptr<CObject>>
operator()(const std::string& key) const
{
std::shared_ptr<CObject> p;
allocate<CObject>(p);
return { key, p };
}
};
std::string keys[] = { "k1", "k2", "k3" };
std::map<std::string, std::shared_ptr<CObject>> map;
std::transform(std::begin(keys), std::end(keys), std::inserter(map), AllocCObject());
Or if you prefer to use a lambda instead of a function object:
auto allocObject = [] (std::string const& s) {
std::shared_ptr<CObject> p;
allocate<CObject>(p);
return std::make_pair(s, p);
}
Alternatively, somewhat closer to your idea (which looks fine to me):
std::map<std::string, std::shared_ptr<CObject>> map = {
{ "k1", {} }, { "k2", {} }, { "k3", {} }
};
for (auto& e : map)
allocate<CObject>(e.second);
(N.B. I don't think VC++ supports initializing the map from an initializer_list like that, but it's valid C++11.)

Vectors of references to objects

Is it legal to have a vector of references to objects, like the following?
vector<Agent&> seenAgents;
Which would for example be populated by some, but not all of the objects in the scene?
I have a vector of Agent objects, but the vector outlined above should hold references to only the ones each agent can currently see - meaning that the references will be being added and removed all the time.
Is this something the language will allow? And in addition, is there anything else I need to be aware of? If I remove a reference from the vector does it persist anywhere? Is it a memory leak?
I seem to be getting this error on the line declaring the vector:
error C2528: 'pointer' : pointer to reference is illegal
Is this something directly to do with the line or is it most likely occurring somewhere else? It's being initialised in the constructors initialiser list like this:
seenAgents(vector<Agents&>())
You can't have vector of references, as a reference is not copyable assignable and all STL containers are supposed to store copyable assignable items.
But you can make the container to hold pointers. Like this:
vector< Agents* > seenAgents;
This is a little dangerous. You need to be sure that these pointers will remain valid. I mean - if someone deletes an object, pointed by a pointer in this container, the pointer becomes invalid. You need to be sure that this will not happen, because you can't check it (you can't check for NULL, because a pointer will not become NULL, if someone deletes the pointed object).
The best solution here (provided by container with pointers) would be to use some smart pointers - some with reference count, for example; they will guarantee you that the object will exist and that the pointer is valid. And in case that the object, pointed by the smart pointer, is destroyed, you can check it for NULL.
You can use std::reference_wrapper instead in C++11:
std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references.
Example:
#include <functional>
#include <vector>
#include <iostream>
int main(int argc, char *argv[])
{
int a = 5;
int b = 6;
std::vector<std::reference_wrapper<const int>> v;
v.push_back(a);
v.push_back(b);
for (const auto& vi: v)
{
std::cout << vi << std::endl;
}
return 0;
}
https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper
You can't do it. Use pointers.
The Boost library provides PTR_VECTOR which is a better solution than:
vector<T*> foo;
I wanted similar functionality. In the end, here is what I did:
template <class T> class VectorOfRefs : public std::vector<T *> {
public:
inline T & at( const uint64_t i ) {
T * x = std::vector<T *>::at( i );
return *x;
}
};
VectorOfRefs < MyType > myVector;
myVector.push_back( &myInstance0 );
myVector.push_back( &myInstance1 );
// later in the code:
myVector.at( i ).myMethod();
Obviously this is a vector of pointers underneath the covers.
Normally I would use STL and settle for myVector.at( i )->myMethod(), but I wanted to use the ++ operator, so I had the following two options:
// using STL:
(*myVector.at(i))++;
// or, using my wrapper:
myVector.at( i )++;
I find the notation with the wrapper far preferable in terms of code readability. I don't like the wrapper, per se, but it pays dividends later.

Creating shared_ptr from raw pointer

I have a pointer to an object. I would like to store it in two containers which both have the ownership. So I think I would be good to make it a shared_ptr of C++0x. How could I convert a raw pointer to a shared_pointer?
typedef unordered_map<string, shared_ptr<classA>>MAP1;
MAP1 map1;
classA* obj = new classA();
map1[ID] = how could I store obj in map1??
Thanks
You need to make sure you don't initialize both shared_ptr objects with the same raw pointer, or it will be deleted twice. A better (but still bad) way to do it:
classA* raw_ptr = new classA;
shared_ptr<classA> my_ptr(raw_ptr);
// or shared_ptr<classA> my_ptr = raw_ptr;
// ...
shared_ptr<classA> other_ptr(my_ptr);
// or shared_ptr<classA> other_ptr = my_ptr;
// WRONG: shared_ptr<classA> other_ptr(raw_ptr);
// ALSO WRONG: shared_ptr<classA> other_ptr = raw_ptr;
WARNING: the above code shows bad practice! raw_ptr simply should not exist as a variable. If you directly initialize your smart pointers with the result of new, you reduce your risk of accidentally initializing other smart pointers incorrectly. What you should do is:
shared_ptr<classA> my_ptr(new classA);
shared_ptr<classA> other_ptr(my_ptr);
What's nice is that the code is more concise as well.
EDIT
I should probably elaborate on how it would work with a map. If you had a raw pointer and two maps, you could do something similar to what I showed above.
unordered_map<string, shared_ptr<classA> > my_map;
unordered_map<string, shared_ptr<classA> > that_guys_map;
shared_ptr<classA> my_ptr(new classA);
my_map.insert(make_pair("oi", my_ptr));
that_guys_map.insert(make_pair("oi", my_ptr));
// or my_map["oi"].reset(my_ptr);
// or my_map["oi"] = my_ptr;
// so many choices!
You can use a variety of ways, but reset() would be good:
map1[ID].reset(obj);
And to address the issue of having two maps refer to the same shared_ptr, we can have:
map2[ID] = map1[ID];
Note that the trick in general to avoid a double delete is to try to avoid raw pointers at all.
Hence avoid:
classA* obj = new classA();
map1[ID].reset(obj);
but instead put the new heap object straight into a shared_ptr.