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:
- 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";
}
- 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";
}
- 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:
- F.7: For general use, take T* or T& arguments rather than smart pointers
- F.60: Prefer T* over T& when “no argument” is a valid option
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