Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expose the const and nonconst versions of begin() and end() to iterate member vector with smart pointer

// Cat.h

class Cat
{public:
    void const_meow() const{ ... };
    void meow(){ ... };
};

class CatLibrary
{public:
    std::vector<std::shared_ptr<Cat>>::iterator begin()
    { 
        return m_cat_list.begin();
    }

    // compile error, the compiler complains cannot covert type
    //     from `std::vector<std::shared_ptr<Cat>>::const_iterator` 
    //     to   `std::vector<std::shared_ptr<const Cat>>::const_iterator`
    std::vector<std::shared_ptr<const Cat>>::const_iterator begin() const 
    { 
        return m_cat_list.cbegin();
    }
private:
    std::vector<std::shared_ptr<Cat>> m_cat_list;
};

// main.cpp

CatLibrary cat_library;       
cat_library.add(std::make_shared<Cat>());
cat_library.add(std::make_shared<Cat>());

for(auto& cat: cat_library )
{
   cat->const_meow(); 
   cat->meow(); 
}       
for(const auto& cat: cat_library)
{
   cat->const_meow(); 
   cat->meow();       // hope to compile error due to invoking non_const method of Cat.
}


const CatLibrary& const_cat_library = cat_library;        
for(auto& cat: const_cat_library ) 
{
   cat->const_meow(); 
   cat->meow();       // hope to compile error due to invoking non_const method of Cat.
}
const CatLibrary& const_cat_library = cat_library; 

for(const auto& cat: const_cat_library ) 
{
   cat->const_meow(); 
   cat->meow();       // hope to compile error due to invoking non_const method of Cat.
}

I want my CatLibrary expose the non-const begin() and non-const end() in which a client can iterate the smart pointer pointing to the mutable Cat. And the const begin() and const end() return the iterator which points the immutable one.

Then when the client iterates the const CatLibrary, I would not worry he could modify the content of Cat in library.

But the const added to my member function begin() only qualifies the pointer to be a const pointer, not the Cat it points.

Without the pointer involved, the vector with constness makes the iterator point to a element with constness also. But I want this effect also applies the element pointed by smart pointer.

I have a approach to solve my problem, but I am not sure what problems would happen in future use.

Maintain two vectors in const and nonconst

#include <iostream>
#include <memory>
#include <vector>

class Cat
{public:
    void const_meow() const { std::cout << "meow" << std::endl;}
    void meow() { std::cout << "meow" << std::endl;}
};


class CatLibrary
{public:

    void add(std::shared_ptr<Cat> cat)
    {
        m_cat_list.push_back(cat);
        m_cat_const_list.push_back(cat);
    };

    std::vector<std::shared_ptr<Cat>>::const_iterator begin()
    { 
        return m_cat_list.begin();
    }

    std::vector<std::shared_ptr<const Cat>>::const_iterator begin() const
    { 
        return m_cat_const_list.begin();
    }

    std::vector<std::shared_ptr<Cat>>::const_iterator end()
    { 
        return m_cat_list.end();
    }

    std::vector<std::shared_ptr<const Cat>>::const_iterator end() const
    { 
        return m_cat_const_list.end();
    }


private:
    std::vector<std::shared_ptr<Cat>> m_cat_list;
    std::vector<std::shared_ptr<const Cat>> m_cat_const_list;
};


int main()
{
   CatLibrary cat_library;

   cat_library.add(std::make_shared<Cat>());
   cat_library.add(std::make_shared<Cat>());
   cat_library.add(std::make_shared<Cat>());

   const CatLibrary& const_cat_library = cat_library;
   for(auto& cat: cat_library)
   {
      cat->meow();
   }

   return 0;
}

Or is there another solution to solve this kind of constness problem on smart pointer in vector?

like image 554
Chen OT Avatar asked Aug 06 '14 06:08

Chen OT


1 Answers

In the example you posted there is no need for the const versions of begin() and end(). You can use a const reference in the ranged based for loop without having const versions of those functions and you don't need the cat to be const auto& at all to call the const member function.

There may be the need of const begin() and end() if your cat_library object itself would be const, but then you couldn't add items like that.

like image 196
nh_ Avatar answered Oct 05 '22 19:10

nh_