Home > Blockchain >  How to cycle through smart pointer to a class with custom iterator
How to cycle through smart pointer to a class with custom iterator

Time:10-30

I have a smart pointer to a class with custom iterator. I need to iterate through it and couldn't find any examples.

struct SomeContrainer
{
   int a;
}

struct ListClass
{
   std::vector<SomeContrainer>::iterator begin() { return m_devs.begin(); }
   std::vector<SomeContrainer>::iterator end()   { return m_devs.end();   }                                         

   void add( const SomeContrainer& dev ) { m_devs.push_back( dev ); }

   private:
      std::vector<SomeContrainer> m_devs;
};

typedef std::unique_ptr<ListClass> ListPtr_t;


void Foo_Add( const ListPtr_t& list )
{
   SomeContrainer dev1, dev2;
   dev1.a = 10;
   dev2.a = 100;
   list->add(dev1);
   list->add(dev2);
}

void DoSomeWorkOtherList( const ListPtr_t& list )
{
   for( auto const& dev : list )    // <-- how to iterate over list ???
   {}
}

// -----------

ListPtr_t pMyList( new ListClass() );

Foo_Add( pMyList );
DoSomeWorkOtherList(pMyList );

It works fine if I don't use a smart pointer and have just an object ListClass list I'm using C 11 and can't upgrade.

CodePudding user response:

you need to dereference it

void DoSomeWorkOtherList( const ListPtr_t& list ) // void(const unique_ptr<ListClass>&)
{
   for( auto const & dev : *list ) // <-- how to iterate other list ???
   {}
}

Not necessary for the code in question, but you probably also want to provide const version of begin and end.

std::vector<SomeContrainer>::const_iterator begin() const { return m_devs.begin(); }
std::vector<SomeContrainer>::const_iterator end() const { return m_devs.end();   }                                         

CodePudding user response:

You have different options, to name a few:

  1. Pass a const reference to the list.
void DoSomeWorkOtherList(const ListClass& list)
{
   std::cout << "v1 (const ListClass&): ";
   for (const auto& dev : list) { std::cout << dev.a << " "; }
   std::cout << "\n";
}
  1. Pass a const raw pointer to the list.
void DoSomeWorkOtherList(const ListClass* list)
{
   std::cout << "v2 (const ListClass*): ";
   if (list)
   {
      for (const auto& dev : *list) { std::cout << dev.a << " "; }
   }
   std::cout << "\n";
}
  1. Pass a const reference to a unique pointer to the list.
void DoSomeWorkOtherList(const ListPtr_t& list)
{
   std::cout << "v3 (const ListPtr_t&): ";
   if (list)
   {
      for (const auto& dev : *list) { std::cout << dev.a << " "; }
   }
   std::cout << "\n";
}

In order to decide what option suits you best it would be helpful to refer to the C Core Guidelines. General recommendation is to use pointers or references if the function code does not imply an ownership change:

A possible caller code for the cases above would be:

int main()
{
    ListPtr_t upl{std::make_unique<ListClass>()};
    upl->add({7});
    upl->add({8});
    DoSomeWorkOtherList(*upl);
    upl->add({9});
    DoSomeWorkOtherList(upl.get());
    Foo_Add(*upl);
    DoSomeWorkOtherList(upl);
}

// Outputs:
//     v1 (const ListClass&): 7, 8
//     v2 (const ListClass*): 7, 8, 9
//     v3 (const ListPtr_t&): 7, 8, 9, 10, 100

Demo

  • Related