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 misunderstanding 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;
Related
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.
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.
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++.
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>(...));
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;