Question

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

    using namespace std;

    class MyPair: public pair<string, int>
    {
        int _ref;
    public:
        MyPair(): pair<string, int>(), _ref(0) {}
        MyPair(string arg1, int arg2): pair<string, int>(arg1, arg2), _ref(0) {}
        ~MyPair();
        void inc() {
            _ref++;
        }
        void dec() {
            _ref--;
            if (_ref == 0) delete this;
        }
    };

    class MyMap: public map<string, int>
    {
    public:
        MyMap(): map<string, int>() {}
        MyMap(const map<string, int>& mp): map<string, int>(mp) {
            //for(auto i=begin(); i!=end(); ++i) i->inc();
            //I want to perform that instruction above, but it gives me an error
        }
        ~MyMap() {
            //for(auto i=begin(); i!=end(); i++) i->dec();
            //same as here
        }
        void insertNewPair(MyPair * mypair) {
            insert(*mypair);
            mypair->inc();
        }
    };

    int main(int argc, char **argv)
    {
        MyMap mymap;
        mymap.insertNewPair(new MyPair("1", 1));
        mymap.insertNewPair(new MyPair("2", 2));
        cout << "mymap[\"1\"] = " << mymap["1"] << endl;
        cout << "mymap[\"2\"] = " << mymap["2"] << endl;
        return 0;
    }

I subclassed a class from std::pair so that I can append a reference counter in it. I named it "MyPair". I also subclassed from std::map and I named it "MyMap". So that everytime I insert new MyPair in MyMap, it calls the inc() member function of MyPair, so that MyPair would increment its _ref member which is the counter of its reference. If I delete an instance of MyMap, it decrements all the _ref member function of each of its contained MyPairs. If _ref in MyPair hits 0, it means that it was no longer referenced, so it will delete itself.

That code above works, because I managed to comment some lines of codes there in MyMap. When I uncomment them, the compiler gives me an error that says that std::pair has no members like inc() and dec(), even though I insert MyPair instances there at the main function. I know that the compiler doesn't notice that I inserted MyPair instances that contains those members, not just a plain std::pair.

Is there's a way that I can call those members of MyPair(inc() and dec()) inside MyMap? Thanks for your answers in advance.

Was it helpful?

Solution

First of all, inheriting from standard containers is a very bad idea.

Secondly, I see many problems in your code:

  • Overuse of dynamic memory: You are using new in places where there is no reason at all. Note that your pair is of std::string and int, that is, 12 bytes per pair with a common std::string implementation (Asumming 32 bits architecture). 4 bytes of the pointer which std::string uses to hold the char array, 4 bytes for the size counter of the string, and 4 bytes for the int of the pair. So there is no reason to use dynamic memory here. If you want to share ownership, use a smart_pointer or a reference wrapper like std::reference_wrapper.

  • Following from the problem above, overuse of error-prone raw-pointers. As I said, smart pointers are a better alternative.

Finally, I think your compiler error is generated due to slicing: std::map uses std::pair internally to store the values. When you insert your pair, that pair is sliced, because std::map::insert espects const std::pair& as argumment and a reference of a derived class is casted implicitly to a reference of a base class.
So, as the compiler says, the pair (std::pair) has no members inc() and dec().

You are inheriting from std::pair, not std::pairis inheriting from your pair class. Consider the tipical inheritance example:

class animal
{
    void eat();
};

class dog : public animal
{
    void bark();
};

The point here is the dog is an animal, but the animal is not a dog (Not all animals are dogs). So the dog can eat because it is an animal, and bark because its a dog. But the animal can't bark, because conceptually its not a dog.
So if you see a dog as if it was an animal only, the dog cannot bark.

OTHER TIPS

You use auto which finds out that the type (returned by begin) is a map. And map has no inc. Maybe implement std::begin( MyMap ) to retrive the right iterator.

But You should probably not derivate, and more wrap a pair.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top