error C2440: 'initializing' : cannot convert from 'std::vector<_Ty>' to 'const std::vector<_Ty> &`

11,847

Solution 1

In the view of the C++ compiler, shared_ptr<BaseClass> and shared_ptr<DerivedClass> are different, unrelated types. While the compiler knows, that normal Pointers can be converted from Derived* to Base*, it does not know that conceptually the same should apply for shared_ptrs, because it does not know "smart pointers" being pointer-like.

The same applies for vector or for templates in general: two instantiations of a template are two different class, with no relation betwen them (if not designed explicitly). So the compiler sees a vector<Something> bound to a reference to a vector<SomethingElse> which are not related types, so the reference binding fails.

But even if the types were somehow related, the binding would fail:

long l = 5;
int& ir = l; //ERROR

Solution 2

shared_ptr<BaseClass> and shared_ptr<SubClass> are distinct, unrelated types, so there's no way for a vector of one to alias a vector of the other, because there's no guarantee that their object layout is the same.

This means that to e.g. pass const std::vector<boost::shared_ptr<BaseClass> >& to a function you'll have to construct a temporary vector of the desired type. You can however do this without incrementing the reference counts on the shared pointers, using shared pointer aliasing:

#include <vector>
#include <memory>

struct B {};
struct D: public B {};

template<typename T, typename U>
std::vector<std::shared_ptr<T>> shared_vector_static_cast(
   const std::vector<std::shared_ptr<U>> &v)
{
   std::vector<std::shared_ptr<T>> w;
   for (const std::shared_ptr<U> &p: v)
      w.push_back(std::shared_ptr<T>(std::shared_ptr<void>(), p.get()));
   return w;
}

int main() {
    std::vector<std::shared_ptr<D>> v{std::make_shared<D>()};
    const std::vector<std::shared_ptr<B>> &w = shared_vector_static_cast<B>(v);
}
Share:
11,847

Related videos on Youtube

q0987
Author by

q0987

Updated on July 17, 2022

Comments

  • q0987
    q0987 almost 2 years

    Question1> Why the following code doesn't work?

    Question2> What is the correct way to design it?

    #include <iostream>
    #include <vector>
    #include "boost/shared_ptr.hpp"
    
    using namespace std;
    
    class BaseClass
    {};
    
    class SubClass : public BaseClass
    {};
    
    int main()
    {
        std::vector<boost::shared_ptr<SubClass> > vecSubClassShared;
    
        boost::shared_ptr<SubClass> sub1(new SubClass);
    
        vecSubClassShared.push_back(sub1);
    
        // Error    1   error C2440: 'initializing' : cannot convert from 'std::vector<_Ty>' to 'const std::vector<_Ty> &`
        const std::vector<boost::shared_ptr<BaseClass> >& vecBaseShared = vecSubClassShared;
    }
    
  • q0987
    q0987 about 11 years
    There is a bug in the code. The size of w is the end is 2*v.size() rather than v.size().