Bellow I provide the complete code for something really simple which I'm struggling with..
Please check below the two comments I say "ERROR" to see where the problem is.
My questions are:
Thanks in advance :)
#include <map>
#include <string>
#include <memory>
class House
{
public:
House(const char* name) : _name(name) {};
~House() {};
std::string getHouseName () { return _name; }
private:
std::string _name;
House(const House& copy)
{
}
House& operator=(const House& assign)
{
}
};
class Obj
{
public:
Obj()
{
InitObj();
}
~Obj() {};
House& getHouse (const char *houseName)
{
std::string name = houseName;
auto i = _myHouseMap.find(name);
//this string doesn't exist on map? then create a new house and add to the map and return the reference to it
if (i == _myHouseMap.end())
{
//create a new house
House h(houseName);
//add to the map
_myHouseMap.insert(std::pair<const std::string, House>(houseName, h));
//return the reference to the house created
return h; //<--- ERROR!!!! need to return the reference!
}
return (i->second);
}
private:
Obj(const Obj& copy);
Obj& operator=(const Obj& assign);
typedef std::map<const std::string, House> myHouseMap;
myHouseMap _myHouseMap;
//the initialization will add one object to my map
void InitObj()
{
House h("apartment");
_myHouseMap.insert(std::pair<const std::string, House>("apartment", h)); //<--- ERROR see reference to function template instantiation 'std::pair<_Ty1,_Ty2>::pair<const char(&)[10],House&>
}
};
int main(void)
{
Obj aaa;
House& myHouse1 = aaa.getHouse ("apartment");
std::cout << "House is " << myHouse1.getHouseName ();
House& myHouse2 = aaa.getHouse ("newHouse"); //here a new house must be created and added to the map
std::cout << "House is " << myHouse2.getHouseName ();
return 0;
}
For your first question, you made House
noncopyable (your copy constructor and copy assignment operator are private). The approach you are taking to insert
requires you to make a pair
first, the construction of which will copy the House
you pass in. If you have access to a C++11 compiler, you can still have the value-type of your map be House
and just use emplace
instead:
void InitObj()
{
_myHouseMap.emplace(std::piecewise_construct,
std::forward_as_tuple("apartment"), //key
std::forward_as_tuple("apartment")); //value
}
If you don't have access to a C++11 compiler, you will have to change the value type to be House*
or some equivalent copy-constructible type.
For the second question, std::map::insert
(and emplace
) return a pair<iterator, bool>
. Just take advantage of that:
if (i == _myHouseMap.end())
{
House h(houseName);
// we insert our new house into the map
// insert() will return a pair<iterator, bool>.
// the bool will be true if the insert succeeded - which we know
// it will because we know that this key isn't already in the map
// so we just reassign 'i' to be insert().first, the new iterator
// pointing to the newly inserted element
i = _myHouseMap.insert(std::pair<const std::string, House>(houseName, h)).first;
}
// here i either points to the element that was already in the map
// or the new element that we just inserted. either way,
// we want the same thing
return i->second;