C++ inserting unique_ptr in map - c++

I have a C++ object of type ObjectArray
typedef map<int64_t, std::unique_ptr<Class1>> ObjectArray;
What is the syntax to create a unique_ptr to a new object of type Class1 and insert it into an object of type ObjectArray?

As a first remark, I wouldn't call it ObjectArray if it is a map and not an array.
Anyway, you can insert objects this way:
ObjectArray myMap;
myMap.insert(std::make_pair(0, std::unique_ptr<Class1>(new Class1())));
Or this way:
ObjectArray myMap;
myMap[0] = std::unique_ptr<Class1>(new Class1());
The difference between the two forms is that the former will fail if the key 0 is already present in the map, while the second one will overwrite its value with the new one.
In C++14, you may want to use std::make_unique() instead of constructing the unique_ptr from a new expression. For instance:
myMap[0] = std::make_unique<Class1>();

If you want to add an existing pointer to insert into the map, you will have to use std::move.
For example:
std::unique_ptr<Class1> classPtr(new Class1);
myMap.insert(std::make_pair(0,std::move(classPtr)));
or similar:
myMap[0] = std::move(classPtr);
if one wants insert a new or overwrite an already resisting key.

In addition to previous answers, I wanted to point out that there is also a method emplace (it's convenient when you cannot/don't want to make a copy), so you can write it like this:
ObjectArray object_array;
auto pointer = std::make_unique<Class1>(...); // since C++14
object_array.emplace(239LL, std::move(pointer));
// You can also inline unique pointer:
object_array.emplace(30LL, std::make_unique<Class1>(...));

Related

Delete a key/value pair from an unordered_map C++

I have two questions. First I have an std::unordered_map<int,Object*> where Object looks like this:
// Object.hpp
class Object {
public:
Object();
~Object(){};
int Id();
void setId(int i);
private:
int id;
};
This unordered_map is put in a class called DataSet which is used as a container to hold all of these objects. In DataSet I want to be able to properly erase a key/value pair given an integer id from Object.
To do this I tried to create an iterator that finds the key by id, and then deletes the pointer to the iterator, and finally erases the key/value pair. It looks like this:
int DataSet::deleteObject(int id)
{
std::unordered_map<int,Object*>::iterator found_it = objects.find(id);
if(found_it != objects.end()) {
delete *found_it;
objects.erase(found_it);
}
return 1;
}
However, when I compile it I get this error:
dataset.cpp:44:9: error: cannot delete expression of type 'value_type'
(aka 'pair<key_type, mapped_type>')
delete *found_it;
Is there a correct way to erase the Object at that location?
Second, when writing a clear() method, I realize I can't just do objects.clear(), so I was wondering if there was a way to actually clear the unordered_map.
For example when I used a std::vector I was able to do this:
std::vector<Object *>::reverse_iterator object;
for(object = objects.rbegin(); object < objects.rend(); object++)
delete(*object);
objects.clear();
But that won't work now for an unordered_map, so what is the right way to do this? The requirements that I am under make it so I can't change Object, or how the unordered_map is set up.
The first part of the question is quite simple: the iterator reference the value and a given location which is of type std::pair<int const, Object*>. You can't delete such an object. You'll get the pointer using the second part of the object, e.g.:
delete found_it->second;
However, it is actually quite uncommon and error-prone to take care of this kind of maintenance. You are much better off not storing an Object* but rather a std::unique_ptr<Object>: the std::unique_ptr<Object> will automatically release the object upon destruction. That would also simplify removing an element:
int DataSet::deletObject(int id) {
return objects.erase(id);
}
When storing std::unique_ptr<Object> you'll probably need to be a bit more verbose when inserting elements into the container, though, e.g.:
objects.insert(std::make_pair(key, std::unique_ptr<Object>(ptr)));
Given that your Object class doesn't have any virtual functions you could probably just store an Object directly, though:
std::unordered_map<int, Object> objects;
Dereferencing an unordered_map::iterator produces a unordered_map::value_type&, i.e. pair<const Key, Value>&.
You want
delete found_it->second;
objects.erase(found_it);
Stepping back a bit, are you sure you even need std::unordered_map<int,Object*> instead of std::unordered_map<int,Object>? If you use the latter you wouldn't have to worry about deleteing anything.
If you do need the mapped_type be an Object* you should use std::unordered_map<int,std::unique_ptr<Object>>. Again, this makes it unnecessary to manually delete the values before erasing an entry from the map.
Also, if Object is the base class for whatever types you're going to be adding to the map, don't forget that it needs a virtual destructor.

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++.

Inserting an element with pointer to std::map using Index operator

Say I have an std::map type which for example is defined as follows.
std::map<int, int>* someMap;
If I weren't using a pointer, I could simply add an element using the index operator. However in this case, since I have a pointer, would the following be the correct way to insert using the index operator.
(*someMap)[someIndex] = someValue;
Yes. The operator [] is overloaded for the Map class. It has to be used directly with the object.
Make sure you point someMap at something. Otherwise, its just contains a meaningless address derived from garbage on the stack. Here's an example allocating from the heap:
std::map<int, int>* someMap = new std::map<int, int>();
and once thats done, yes, you are correct in how to use it:
(*someMap)[someIndex] = someValue;
and be sure to cleanup after yourself
delete someMap;
Yes, your code is fine:
(*someMap)[someIndex] = someValue;

How to initialize a constant map pointer to be empty in C++?

Simple question, I just want to initialize a map to be empty, instead of being a nullptr.
const std::map<std::string, std::string>* emptyDictionary;
I tried
const std::map<std::string, std::string>* emptyDictionary = {"", ""};
but obviously that's not right.
Thanks guys.
You forgot to make any map at all -- you just made a pointer! You can make the pointer point to a dynamically allocated map:
const std::map<std::string, std::string>* emptyDictionary
= new std::map<std::string, std::string>;
This map will be truly empty. If you add the initializer {{"", ""}}, which you may well do, then you don't actually have an empty map, but rather a map with one element which maps an empty string to an empty string.
Note that you can never modify your map through the const pointer, so it's a bit questionable why you'd want to do this.
Note also that wanton dynamic allocation is generally a poor programming style. There's almost surely a better way to do whatever you need to do, or, based on your comment, you're just grossly mis­under­stand­ing something: The best way to obtain a pointer is to take the address of an existing object:
std::map<std::string, std::string> m;
foo(&m); // pass address of m as a pointer
const std::map<std::string, std::string>* emptyDictionary
= new std::map<std::string, std::string>();
The default (empty) constructor of map will create an empty map http://www.cplusplus.com/reference/stl/map/map/.
Either declare the map with automatic allocation on the stack by just writing
std::map<std::string, std::string> emptyDictionary();
And send it to your function using the addres-off operator
yourfunction(&emptyDictionary);
However, if the dictionary will outlive the instance of it was created, you need to dynamically allocate it instead to avoid a call to its destructor.
const std::map<std::string, std::string>* emptyDictionary = new std::map<std::string, std::string>();
Then you dont need the address-of operator when calling your function.
yourfunction(emptyDictionary);
However, the responsibility of deallocation will then be yours. When you dont need the object any longer, you need to delete the object using the delete statement.
delete emptyDictionary;

C++ STL map with a custom class as second type

I'd like to create a map with an int and my own custom class. Is there a way to do this?
map<int, MyClass> myMap;
If not, how do I go about accomplishing this? Basically, I want an id(or preferably an enum) to point to my own custom class. In most other languages, this would be a simple hash.
#include <map>
std::map<int, MyClass> myMap;
MyClass foo;
myMap[5] = foo;
myMap[5].bar = 10;
You do need MyClass to be default- and copy- constructible, so it can be created (if you use, e.g., myMap[5]) and copied into the map.
Yes the only condition are:
The key Type is comparable (Good)
The value Type is copy constructable ?
So you just need to make sure you are object is copy constructable so that it can be copied into the map.
you should use like this
typedef std::map myMapType;
myMapType myMap;
But be careful when inserting your class in this as if you insert more than one time for same key, you will never get a notice :
Call myMapType::iterator itr myMap.find(key) , depending upon return type and your program requirments you can procced.
Like wise try to avid access any element using [] operator like
somefunc(myMap[10]);
As you will not get an error from map even there was noting inserted for key 10