0
    #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.

Andy Autida
  • 449
  • 1
  • 5
  • 5
  • 9
    Deriving from them is bad enough. Doing so publicly is asking for trouble. – chris Sep 01 '13 at 16:38
  • Try to explain more clearly what you are doing. You just want to create a referenced counted pair. (this 5 words sum up your paragraph) Also try to show what does not work clearly. (Here show the error from the compiler, and let the code as it is withou commenting what is wrong) – dzada Sep 01 '13 at 17:04
  • As already explained this os very bad code. I would suggest you to read some good book on C++ like Effective C++, Effective STL and other similar titles. Modern C++ has all the tools so that no ne would ever write such code. – Phil1970 Jul 23 '17 at 23:41

2 Answers2

2

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.

Community
  • 1
  • 1
Manu343726
  • 13,969
  • 4
  • 40
  • 75
  • Thanks. It's very informative. I'll do what you suggests (usage of std::reference_wrapper) later. But I think I will make my program slow if I'm gonna make my own container, that's why I chose to subclass from std::map and get advantage with the search algorithm it implements in finding key values. Thanks again for your help. – Andy Autida Sep 02 '13 at 01:13
0

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.

dzada
  • 5,344
  • 5
  • 29
  • 37