Loading ...
Sorry, an error occurred while loading the content.

[boost] shared_ptr w/ STL algorithm for_each

Expand Messages
  • John Hunter
    I have a piece of sample code in which I have a vector of shared pointers (boost::shared_ptr ). Can anyone tell me why I am unable to iterate using the STL
    Message 1 of 2 , Nov 1, 1999
    • 0 Attachment
      I have a piece of sample code in which I have a vector of shared
      pointers (boost::shared_ptr<>). Can anyone tell me why I am unable to
      iterate using the STL algorithm for_each (fail to compile; message
      below) but I can manually loop over the container just fine.

      e.g.
      //this works
      vector<Aptr>::iterator ix;
      for (ix = x.begin(); ix != x.end(); ++ix)
      (*ix)->print();

      //this doesn't
      std::for_each(x.begin(), x.end(), std::mem_fun(&Base::print));

      Thanks in advace; complete code and compiler error message below.

      John Hunter

      Code:
      #include <iostream>
      #include <string>
      #include <map>
      #include <memory>
      #include <vector>
      #include <algorithm>
      #include <boost/smart_ptr.hpp>

      class Base {
      public:
      virtual ~Base() {};
      virtual void print() = 0;
      virtual Base* clone() const { } ;
      };

      class Foo : public Base {
      int x;
      public:
      Foo() : x(0) {};
      ~Foo () { std::cout << "Foo: ouch" << endl; }
      void print() { std::cout << "I am Foo" << endl;}
      Foo* clone() const { return new Foo(*this); }
      };

      class Bar : public Base {
      int x;
      public:
      Bar() : x(0) {};
      ~Bar () { std::cout << "Bar: ouch" << endl; }
      void print() { std::cout << "I am Bar" << endl;}
      Bar* clone() const { return new Bar(*this); }
      };

      int main() {

      const Foo foo;
      const Bar bar;

      typedef std::map<const std::string, const Base*> Map;
      Map m;
      m["foo"] = &foo;
      m["bar"] = &bar;

      typedef boost::shared_ptr<Base> Aptr;
      vector<Aptr> x;

      std::string s;
      std::cout << "enter foo or bar" << endl;
      while (cin >> s)
      x.push_back(Aptr(m[s]->clone())); //use the constructor

      //this works
      vector<Aptr>::iterator ix;
      for (ix = x.begin(); ix != x.end(); ++ix)
      (*ix)->print();

      //this doesn't
      std::for_each(x.begin(), x.end(), std::mem_fun(&Base::print));
      }


      Compiler error message:
      localhost:~/c/examples> g++ test.cpp
      g++ test.cpp

      /usr/local/lib/gcc-lib/i586-pc-linux-gnu/2.95/../../../../include/g++-3/stl_algo.h:
      In function `class mem_fun_t<void,Base> for_each<main()::Aptr *,
      mem_fun_t<void,Base> >(main()::Aptr *, main()::Aptr *,
      mem_fun_t<void,Base>)':
      test.cpp:58: instantiated from here
      /usr/local/lib/gcc-lib/i586-pc-linux-gnu/2.95/../../../../include/g++-3/stl_algo.h:83:
      no match for call to `(mem_fun_t<void,Base>) (boost::shared_ptr<Base>
      &)'
      /usr/local/lib/gcc-lib/i586-pc-linux-gnu/2.95/../../../../include/g++-3/stl_function.h:566:
      candidates are: void mem_fun_t<void,Base>::operator ()(Base *) const
      localhost:~/c/examples>
    • Matthew D. Langston
      Hi John, The problem is due to the fact that there is no conversion from shared_ptr to Base* . Why is this conversion trying to take place? To see
      Message 2 of 2 , Nov 1, 1999
      • 0 Attachment
        Hi John,

        The problem is due to the fact that there is no conversion from
        "shared_ptr<Base>" to "Base*". Why is this conversion trying to take
        place? To see why, let's look back at your call to "for_each":

        std::for_each(x.begin(), x.end(), std::mem_fun(&Base::print));

        The "mem_fun" helper function is returning an object (a
        "mem_fun_t<void,Base>" in this case) whose "operator ()" takes a "Base*"
        as an argument. However, the call to "for_each" is passing a
        "shared_ptr<Base>" element to "operator ()" on each iteration, and there
        is no conversion from "shared_ptr<Base>" to "Base*".

        The right way to do what you want to do is to have a complimentary set
        of "mem_fun_*" objects whose "operator ()" takes a "shared_ptr<T>"
        instead of a "T*". I have designed a small extension to the boost
        library which does just this, and I have attached it to this e-mail as
        the file "functional_boost.hxx". Note that my "mem_fun_*" objects are
        not specific to boost - they should work with *all* smart pointers (that
        was the goal of my design anyway).

        Please note that I have heretofore not submitted this work to the boost
        developers because I am not sure if I am happy with my design. However,
        my "boost extension" library does work (I use it in my projects), and so
        it is probably mature enough for a general discussion on the boost list
        if there is interest. If it is not my current design, or some version
        thereof, then we (the "boost users and developers") need to design such
        an extension to the boost library because this style of problem crops up
        all of the time (at least in my work, and for those people I help).

        Another reason I have heretofore not submitted my "boost extension"
        library is because I have not documented it (other than the comments in
        the code). With these caveats, perhaps you will find my attachment
        useful. FYI, my "boost extension" library is currently in the namespace
        MDL, not "boost". Here is how you would use it in your case:

        std::for_each(x.begin(), x.end(), MDL::mem_fun_ptr(&Base::print, boost::shared_ptr<Base>()));

        I have changed the example code that you originally sent in to use
        "MDL::mem_fun_ptr" - it is also attached to this e-mail as the file
        "mem_fun_ptr.cxx". I tested it using gcc 2.95.2 under RedHat Linux 6.1
        Intel.

        --
        Matthew D. Langston
        SLD, Stanford Linear Accelerator Center
        langston@...


        John Hunter wrote:
        >
        > I have a piece of sample code in which I have a vector of shared
        > pointers (boost::shared_ptr<>). Can anyone tell me why I am unable to
        > iterate using the STL algorithm for_each (fail to compile; message
        > below) but I can manually loop over the container just fine.
        >
        > e.g.
        > //this works
        > vector<Aptr>::iterator ix;
        > for (ix = x.begin(); ix != x.end(); ++ix)
        > (*ix)->print();
        >
        > //this doesn't
        > std::for_each(x.begin(), x.end(), std::mem_fun(&Base::print));
        >
        > Thanks in advace; complete code and compiler error message below.
        >
        > John Hunter
        >
        > Code:
        > #include <iostream>
        > #include <string>
        > #include <map>
        > #include <memory>
        > #include <vector>
        > #include <algorithm>
        > #include <boost/smart_ptr.hpp>
        >
        > class Base {
        > public:
        > virtual ~Base() {};
        > virtual void print() = 0;
        > virtual Base* clone() const { } ;
        > };
        >
        > class Foo : public Base {
        > int x;
        > public:
        > Foo() : x(0) {};
        > ~Foo () { std::cout << "Foo: ouch" << endl; }
        > void print() { std::cout << "I am Foo" << endl;}
        > Foo* clone() const { return new Foo(*this); }
        > };
        >
        > class Bar : public Base {
        > int x;
        > public:
        > Bar() : x(0) {};
        > ~Bar () { std::cout << "Bar: ouch" << endl; }
        > void print() { std::cout << "I am Bar" << endl;}
        > Bar* clone() const { return new Bar(*this); }
        > };
        >
        > int main() {
        >
        > const Foo foo;
        > const Bar bar;
        >
        > typedef std::map<const std::string, const Base*> Map;
        > Map m;
        > m["foo"] = &foo;
        > m["bar"] = &bar;
        >
        > typedef boost::shared_ptr<Base> Aptr;
        > vector<Aptr> x;
        >
        > std::string s;
        > std::cout << "enter foo or bar" << endl;
        > while (cin >> s)
        > x.push_back(Aptr(m[s]->clone())); //use the constructor
        >
        > //this works
        > vector<Aptr>::iterator ix;
        > for (ix = x.begin(); ix != x.end(); ++ix)
        > (*ix)->print();
        >
        > //this doesn't
        > std::for_each(x.begin(), x.end(), std::mem_fun(&Base::print));
        > }
        >
        > Compiler error message:
        > localhost:~/c/examples> g++ test.cpp
        > g++ test.cpp
        >
        > /usr/local/lib/gcc-lib/i586-pc-linux-gnu/2.95/../../../../include/g++-3/stl_algo.h:
        > In function `class mem_fun_t<void,Base> for_each<main()::Aptr *,
        > mem_fun_t<void,Base> >(main()::Aptr *, main()::Aptr *,
        > mem_fun_t<void,Base>)':
        > test.cpp:58: instantiated from here
        > /usr/local/lib/gcc-lib/i586-pc-linux-gnu/2.95/../../../../include/g++-3/stl_algo.h:83:
        > no match for call to `(mem_fun_t<void,Base>) (boost::shared_ptr<Base>
        > &)'
        > /usr/local/lib/gcc-lib/i586-pc-linux-gnu/2.95/../../../../include/g++-3/stl_function.h:566:
        > candidates are: void mem_fun_t<void,Base>::operator ()(Base *) const
        > localhost:~/c/examples>
      Your message has been successfully submitted and would be delivered to recipients shortly.