Home > Software engineering >  How to make a C map with class as value with a constructor
How to make a C map with class as value with a constructor

Time:09-25

I have a class that has a constructor. I now need to make a map with it as a value how do I do this? Right now without a constructor I do.

#include <iostream>
#include <map>
using namespace std;

class testclass {
public:
  int x = 1;
};

int main()
{
  map<int,testclass> thismap;
  testclass &x = thismap[2];
}

If I added a constructor with arguments how would I add them to the map? I basically need to do

#include <iostream>
#include <map>
using namespace std;

class testclass {
public:
  int x = 1;
  testclass(int arg) {
    x = arg;
  }
};

int main()
{
  map<int,testclass> thismap;
  testclass &x = thismap[2];
}

This obviously wouldn't work since it requires an argument but I can't figure a way of doing this.

CodePudding user response:

Using std::map::operator[] requires that the mapped type is default-constructible, since it must be able to construct an element if one doesn't already exist.

If your mapped type is not default-constructible, you can add elements with std::map::emplace, but you still can't use std::map::operator[] to search, you will need to use std::map::find() or so.

CodePudding user response:

This is how you can add items of your own class to your map. Note : I used a string in testclass to better show difference between key and value/class.

#include <iostream>
#include <string>
#include <map>

class testclass
{
public:
    explicit testclass(const std::string& name) :
        m_name{ name }
    {
    };

    const std::string& name() const
    {
        return m_name;
    }

private:
    std::string m_name;
};

int main()
{
    std::map<int, testclass> mymap;

    // emplace will call constructor of testclass with "one", and "two"
    // and efficiently place the newly constructed object in the map
    mymap.emplace(1, "one"); 
    mymap.emplace(2, "two");

    std::cout << mymap.at(1).name() << std::endl;
    std::cout << mymap.at(2).name() << std::endl;
}

CodePudding user response:

That's a rather obvious feature of std::map (and very similar other std containers). Some of their operations require specific type requirements for good reasons.

There is no problem to create such a map as you suggest in the first place, however, you are restricted to method calls that do not require potential default construction. The operator[] is such a method, since in the case the element is not found, it is created. That is what does not work in your example. Just use other methods with little impact on the map usage and you can still succeed:

#include <iostream>
#include <map>
using namespace std;

class testclass {
public:
  int x = 1;
  testclass(int arg) {
    x = arg;
  }
};

int main()
{
  map<int,testclass> thismap;
  thismap.insert( {2, testclass(5)} );
  
  auto element2 = thismap.find(2);
  if (element2 != thismap.end()) {
    testclass& thiselement = element2->second;
    cout << "element 2 found in map, value=" << thiselement.x << endl;
  }

  auto element5 = thismap.find(5);
  if (element5 == thismap.end()) {
    cout << "no element with key 5 in thismap. Error handling." << endl;
  } 
}

Main issue: avoid operator[].

  •  Tags:  
  • c
  • Related