Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generalized copy constructors

Why do classes like shared_ptr have another template in their constructors?

For example:

template<class T> class shared_ptr {
public:
  template<class Y>
  explicit shared_ptr(Y * p);

I've been reading Scott Meyers's Effective C++, item 45, which says the idea behind it is to make polymorphism possible through them; that is, construct shared_ptr<A> from shared_ptr<B> if B is derived from A.

But isn't defining a constructor like

explicit shared_ptr(T * p);

enough? I mean, this code works just fine:

class C1 {
};

class C2 : public C1 {
};

template<typename T>
class A
{
public:
  A(T &a)
  {
    var1 = a;
  }

  T var1;
};

int main(int argc, char *argv[])
{
  C2 c2;
  A<C1> inst1(c2);
}

So why do we need another template for constructor there?

like image 822
Zhani Baramidze Avatar asked May 28 '17 12:05

Zhani Baramidze


People also ask

What are the types of copy constructor?

Copy Constructor is of two types:Default Copy constructor: The compiler defines the default copy constructor. If the user defines no copy constructor, compiler supplies its constructor. User Defined constructor: The programmer defines the user-defined constructor.

What is meant by copy constructor?

Copy Constructor in C++ A copy constructor is a member function that initializes an object using another object of the same class. A copy constructor has the following general function prototype: ClassName (const ClassName &old_obj);

Can there be multiple copy constructor?

A class can have multiple copy constructors, e.g. both T::T(const T&) and T::T(T&). If some user-defined copy constructors are present, the user may still force the generation of the implicitly declared copy constructor with the keyword default .

How many copy constructors can a class have?

Hence, there is always one copy constructor that is either defined by the user or by the system.


1 Answers

Without the template constructor, the following code would have undefined behavior:

#include <memory>

class Base {};
class Derived : public Base {};

int main() {
    std::shared_ptr<Base> ptr( new Derived );
}

If shared_ptr takes only a Base*, it is forced to eventually call delete on that Base* pointer. But since Base does not have a virtual destructor and the pointer actually points at Derived, this is undefined behavior.

But in reality, the code above is well-formed. The template constructor for shared_ptr takes a Derived* pointer and stores a custom deleter that calls delete on the original Derived* pointer, which is fine.

like image 165
aschepler Avatar answered Sep 21 '22 06:09

aschepler