1

I have written an implementation of Shared_ptr as part of working through the C++ Primer book. The header file does compile correctly, however I'm receiving several "No matching function" errors when I try to use it with a `Blob' class.

I've spent a few hours staring at the code and I think the problem is with the constructors, however I'm still a C++ beginner and haven't had any luck fixing it. I previously posted this on code review but was told it was 'off topic' and was instructed to post it here. The other posts on shared_ptr implementations there didn't help. Any feedback to set me in the right direction would be greatly appreciated.

Note: I haven't posted the Blob class as it is quite long, nor have I posted the test class. I'm happy to provide either if requested.

Example errors:

exercise_16.29.h: In instantiation of 'Blob< <template-parameter-1-1> >::Blob(std::initializer_list<_Tp>) [with T = int]':
exercise_16.30.cpp:9:33:   required from here
exercise_16.29.h:58:103: error: no matching function for call to 'my_shared_ptr<std::vector<int, std::allocator<int> > >::my_shared_ptr(std::shared_ptr<std::vector<int, std::allocator<int> > >)'
 template <typename T> Blob<T>::Blob(std::initializer_list<T> il): data(std::make_shared<std::vector<T>>(il)) { }
                                                                                                       ^
In file included from exercise_16.29.h:10:
exercise_16.28-1.h:50:1: note: candidate: 'my_shared_ptr< <template-parameter-1-1> >::my_shared_ptr(const my_shared_ptr< <template-parameter-1-1> >&, void (*)(T*)) [with T = std::vector<int, std::allocator<int> >]'
 my_shared_ptr<T>::my_shared_ptr(const my_shared_ptr &rhs, void (*d)(T*)): p(rhs.p), del(d), count(rhs.count) {
 ^~~~~~~~~~~~~~~~
exercise_16.28-1.h:50:1: note:   candidate expects 2 arguments, 1 provided
exercise_16.28-1.h:44:1: note: candidate: 'my_shared_ptr< <template-parameter-1-1> >::my_shared_ptr(const my_shared_ptr< <template-parameter-1-1> >&) [with T = std::vector<int, std::allocator<int> >]'
 my_shared_ptr<T>::my_shared_ptr(const my_shared_ptr &rhs): p(rhs.p), del(nullptr), count(rhs.count) {
 ^~~~~~~~~~~~~~~~
exercise_16.28-1.h:44:1: note:   no known conversion for argument 1 from 'std::shared_ptr<std::vector<int, std::allocator<int> > >' to 'const my_shared_ptr<std::vector<int, std::allocator<int> > >&'
exercise_16.28-1.h:20:12: note: candidate: 'my_shared_ptr< <template-parameter-1-1> >::my_shared_ptr(T*, void (*)(T*)) [with T = std::vector<int, std::allocator<int> >]'
   explicit my_shared_ptr(T *pt, void (*d)(T*)): p(pt), count(new std::size_t(1)), del(d) { } //shared_ptr<T> p(q, d)
            ^~~~~~~~~~~~~
exercise_16.28-1.h:20:12: note:   candidate expects 2 arguments, 1 provided
exercise_16.28-1.h:19:12: note: candidate: 'my_shared_ptr< <template-parameter-1-1> >::my_shared_ptr(T*) [with T = std::vector<int, std::allocator<int> >]'
   explicit my_shared_ptr(T *pt): p(pt), count(new std::size_t(1)), del(nullptr) { } // shared_ptr<T> p(q)
            ^~~~~~~~~~~~~
exercise_16.28-1.h:19:12: note:   no known conversion for argument 1 from 'std::shared_ptr<std::vector<int, std::allocator<int> > >' to 'std::vector<int, std::allocator<int> >*'
exercise_16.28-1.h:16:3: note: candidate: 'my_shared_ptr< <template-parameter-1-1> >::my_shared_ptr() [with T = std::vector<int, std::allocator<int> >]'
   my_shared_ptr(): p(nullptr), del(nullptr), count(nullptr) { }
   ^~~~~~~~~~~~~
exercise_16.28-1.h:16:3: note:   candidate expects 0 arguments, 1 provided
exercise_16.28-1.h: In instantiation of 'my_shared_ptr< <template-parameter-1-1> >::~my_shared_ptr() [with T = std::vector<int, std::allocator<int> >]':

Shared_ptr implementation:

#ifndef EXERCISE_16_28_1_H
#define EXERCISE_16_28_1_H

#include <cstddef>
#include <algorithm>

template <typename> class my_shared_ptr;

template <typename T> void swap(my_shared_ptr<T>&, my_shared_ptr<T>&);
template <typename T> my_shared_ptr<T> make_shared(T);

template <typename T> class my_shared_ptr {
    friend void swap<T>(my_shared_ptr<T>&, my_shared_ptr<T>&);
    friend my_shared_ptr make_shared<T>(T);
    public:
        my_shared_ptr(): p(nullptr), del(nullptr), count(nullptr) { }
        //my_shared_ptr(T *pt): p(pt), count(new std::size_t(1)), del(nullptr) { }
        //my_shared_ptr(T *pt, void (*d)(T*)): p(pt), count(new std::size_t(1)), del(d) { }
        explicit my_shared_ptr(T *pt): p(pt), count(new std::size_t(1)), del(nullptr) { } // shared_ptr<T> p(q)
        explicit my_shared_ptr(T *pt, void (*d)(T*)): p(pt), count(new std::size_t(1)), del(d) { } //shared_ptr<T> p(q, d)
        my_shared_ptr(const my_shared_ptr&);        // copy constructor
        my_shared_ptr(const my_shared_ptr&, void (*d)(T*)); // copy constructor with deleter
        my_shared_ptr& operator=(my_shared_ptr&);   // copy assignment operator
        ~my_shared_ptr();               // destructor

        T& operator*() const;
        T* operator->() const;

        T* get();
        my_shared_ptr& swap(my_shared_ptr&); 
        bool unique() const;
        std::size_t use_count() const;
        my_shared_ptr& reset();
        my_shared_ptr& reset(T*);
        my_shared_ptr& reset(T*, void (*d)(T*));
    private:
        T* p;
        void (*del)(T*);
        std::size_t *count;
};

// copy constructor
template <typename T>
my_shared_ptr<T>::my_shared_ptr(const my_shared_ptr &rhs): p(rhs.p), del(nullptr), count(rhs.count) { 
    ++*count;
}

// copy constructor with deleter
template <typename T>
my_shared_ptr<T>::my_shared_ptr(const my_shared_ptr &rhs, void (*d)(T*)): p(rhs.p), del(d), count(rhs.count) {
    ++*count;
}

// copy assignment operator
template <typename T>
my_shared_ptr<T>& my_shared_ptr<T>::operator=(my_shared_ptr &rhs) {
    ++*rhs.count;
    --*count;   
    if(--*count == 0) {
        del ? del(p) : delete p;
        del ? del(count) : delete count;
    }
    p = rhs.p;
    del = rhs.del;
    return *this;
}

// destructor
template <typename T>
my_shared_ptr<T>::~my_shared_ptr() {
    if(--*count == 0) {
        del ? del(p) : delete p;
        del ? del(count) : delete count;
    }
    del = nullptr;
}

// dereference operator
template <typename T>
T& my_shared_ptr<T>::operator*() const {
    return *p;
}

// member access operator
template <typename T>
T* my_shared_ptr<T>::operator->() const {
    return & this->operator*();
}

// get
template <typename T>
T* my_shared_ptr<T>::get() {
    return p;
}

// member swap
template <typename T>
my_shared_ptr<T>& my_shared_ptr<T>::swap(my_shared_ptr &rhs) {
    using std::swap;
    swap(p, rhs.p);
    swap(del, rhs.del);
    return *this;
}

// unique
template <typename T>
bool my_shared_ptr<T>::unique() const {
    if (*count == 1)
        return true;
    else
        return false;
}

// use_count
template <typename T>
std::size_t my_shared_ptr<T>::use_count() const {
    return count;
}

template <typename T> my_shared_ptr<T>& my_shared_ptr<T>::reset() {
    if (--*count == 0) {
        delete p;
        delete count;
    }
    del = nullptr;
    return *this;
}

template <typename T> my_shared_ptr<T>& my_shared_ptr<T>::reset(T *t) {
    if (--*count == 0) {
        delete p;
        delete count;
    }
    p = t.p;
    del = nullptr;
    return *this;
}

template <typename T> my_shared_ptr<T>& my_shared_ptr<T>::reset(T *t, void (*d)(T*)) {
    if (--*count == 0) {
        delete p;
        delete count;
    }
    p = t.p;
    del = d;
    return *this;
}

// make_shared
template <typename T>
my_shared_ptr<T> make_shared(T t) {
    return my_shared_ptr<T>(new T(t));
}

// non-member swap
template <typename T> inline void swap(my_shared_ptr<T> &lhs, my_shared_ptr<T> &rhs) {
    using std::swap;
    swap(lhs.p, rhs.p);
    swap(lhs.del, rhs.del);
}

#endif

Update:

Many thanks for the helpful replies so far. Using std::make_shared rather than make_shared was a debugging change I made, however I overlooked the fact that std::make_shared would return std::shared_ptr not my_shared_ptr. I have added the original compiler error message below where Blob uses my implementation of make_shared:

exercise_16.30.cpp:9:33:   required from here
exercise_16.29.h:58:103: error: no matching function for call to 'my_shared_ptr<std::vector<int, std::allocator<int> > >::my_shared_ptr(std::shared_ptr<std::vector<int, std::allocator<int> > >)'
 template <typename T> Blob<T>::Blob(std::initializer_list<T> il): data(make_shared<std::vector<T>>(il)) { }
                                                                                                       ^
In file included from exercise_16.29.h:10:
exercise_16.28-1.h:50:1: note: candidate: 'my_shared_ptr< <template-parameter-1-1> >::my_shared_ptr(const my_shared_ptr< <template-parameter-1-1> >&, void (*)(T*)) [with T = std::vector<int, std::allocator<int> >]'
 my_shared_ptr<T>::my_shared_ptr(const my_shared_ptr &rhs, void (*d)(T*)): p(rhs.p), del(d), count(rhs.count) {
 ^~~~~~~~~~~~~~~~
exercise_16.28-1.h:50:1: note:   candidate expects 2 arguments, 1 provided
exercise_16.28-1.h:44:1: note: candidate: 'my_shared_ptr< <template-parameter-1-1> >::my_shared_ptr(const my_shared_ptr< <template-parameter-1-1> >&) [with T = std::vector<int, std::allocator<int> >]'
 my_shared_ptr<T>::my_shared_ptr(const my_shared_ptr &rhs): p(rhs.p), del(nullptr), count(rhs.count) {
 ^~~~~~~~~~~~~~~~
exercise_16.28-1.h:44:1: note:   no known conversion for argument 1 from 'std::shared_ptr<std::vector<int, std::allocator<int> > >' to 'const my_shared_ptr<std::vector<int, std::allocator<int> > >&'
exercise_16.28-1.h:20:12: note: candidate: 'my_shared_ptr< <template-parameter-1-1> >::my_shared_ptr(T*, void (*)(T*)) [with T = std::vector<int, std::allocator<int> >]'
   explicit my_shared_ptr(T *pt, void (*d)(T*)): p(pt), count(new std::size_t(1)), del(d) { } //shared_ptr<T> p(q, d)
            ^~~~~~~~~~~~~
exercise_16.28-1.h:20:12: note:   candidate expects 2 arguments, 1 provided
exercise_16.28-1.h:19:12: note: candidate: 'my_shared_ptr< <template-parameter-1-1> >::my_shared_ptr(T*) [with T = std::vector<int, std::allocator<int> >]'
   explicit my_shared_ptr(T *pt): p(pt), count(new std::size_t(1)), del(nullptr) { } // shared_ptr<T> p(q)
            ^~~~~~~~~~~~~
exercise_16.28-1.h:19:12: note:   no known conversion for argument 1 from 'std::shared_ptr<std::vector<int, std::allocator<int> > >' to 'std::vector<int, std::allocator<int> >*'
exercise_16.28-1.h:16:3: note: candidate: 'my_shared_ptr< <template-parameter-1-1> >::my_shared_ptr() [with T = std::vector<int, std::allocator<int> >]'
   my_shared_ptr(): p(nullptr), del(nullptr), count(nullptr) { }
   ^~~~~~~~~~~~~
exercise_16.28-1.h:16:3: note:   candidate expects 0 arguments, 1 provided
exercise_16.28-1.h: In instantiation of 'my_shared_ptr< <template-parameter-1-1> >::~my_shared_ptr() [with T = std::vector<int, std::allocator<int> >]':```

As requested I have now included the Blob class and test code:

#ifndef BLOB_H
#define BLOB_H

#include <initializer_list>
#include <vector>
#include <string>
#include <memory>
#include <stdexcept>
#include <iostream>
#include "exercise_16.28-1.h"

template <typename> class BlobPtr;
template <typename> class Blob; // needed for parameters in operators below
template <typename T> bool operator==(const Blob<T>&, const Blob<T>&);
template <typename T> bool operator!=(const Blob<T>&, const Blob<T>&);
template <typename T> bool operator<(const Blob<T>&, const Blob<T>&);
template <typename T> bool operator>(const Blob<T>&, const Blob<T>&);
template <typename T> bool operator<=(const Blob<T>&, const Blob<T>&);
template <typename T> bool operator>=(const Blob<T>&, const Blob<T>&);

template <typename T> class Blob {
    friend class BlobPtr<T>;
    friend bool operator==<T>(const Blob<T>&, const Blob<T>&);
    friend bool operator!=<T>(const Blob<T>&, const Blob<T>&);
    friend bool operator< <T>(const Blob<T>&, const Blob<T>&);
    friend bool operator><T>(const Blob<T>&, const Blob<T>&);
    friend bool operator<=<T>(const Blob<T>&, const Blob<T>&);
    friend bool operator>=<T>(const Blob<T>&, const Blob<T>&);
    public:
        typedef T value_type;
        typedef typename std::vector<T>::size_type size_type;
        // constructors
        Blob();
        Blob(std::initializer_list<T> il);
        template <typename It> Blob(It b, It e);
        // members
        size_type size() const { return data->size(); };
        bool empty() const { return data->empty(); }
        // add and remove elements
        void push_back(const T &t) { data->push_back(t); }
        void push_back(T &&t) { data->push_back(std::move(t)); }
        void pop_back();
        // element access
        T& front();
        T& back();
        const T& front() const;
        const T& back() const;
        T& operator[](size_type);
        const T& operator[](size_type) const;
        BlobPtr<T> begin() const;   // return BlobPtr to the first element
        BlobPtr<T> end() const ;    // and one past the last element
    private:
        my_shared_ptr<std::vector<T>> data;
        void check(size_type i, const std::string &msg) const;
};

template <typename T> Blob<T>::Blob(): data(make_shared<std::vector<T>>()) { }
template <typename T> Blob<T>::Blob(std::initializer_list<T> il): data(make_shared<std::vector<T>>(il)) { }

template <typename T> 
template <typename It> Blob<T>::Blob(It b, It e): data(make_shared<std::vector<T>>(b, e)) {}

template <typename T> void Blob<T>::check(size_type i, const std::string &msg) const {
    if (i >= data->size())
        throw std::out_of_range(msg);
}

template <typename T> T& Blob<T>::front() {
    // if the vector is empty, check will throw
    check(0, "front on empty Blob");
    return data->front();
}

template <typename T> const T& Blob<T>::front() const {
    // if the vector is empty, check will throw
    check(0, "front on empty Blob");
    return data->front();
}

template <typename T> T& Blob<T>::back() {
    check(0, "back on empty Blob");
    return data->back();
}

template <typename T> const T& Blob<T>::back() const {
    check(0, "back on empty Blob");
    return data->back();
}

template <typename T> T& Blob<T>::operator[](size_type i) {
    return data->at(i);
}

template <typename T> const T& Blob<T>::operator[](size_type i) const {
    return data->at(i);
}

template <typename T> void Blob<T>::pop_back() {
    check(0, "pop_back on empty Blob");
    data->pop_back();
}

template <typename T> bool operator==(const Blob<T> &lhs, const Blob<T> &rhs) {
    return *lhs.data == *rhs.data;
}

template <typename T> bool operator!=(const Blob<T> &lhs, const Blob<T> &rhs) {
    return !(lhs == rhs);
}

template <typename T> bool operator<(const Blob<T> &lhs, const Blob<T> &rhs) {
    return *lhs.data < *rhs.data;
}

template <typename T> bool operator>(const Blob<T> &lhs, const Blob<T> &rhs) {
    return rhs < lhs;
}

template <typename T> bool operator<=(const Blob<T> &lhs, const Blob<T> &rhs) {
    return !(lhs > rhs);
}

template <typename T> bool operator>=(const Blob<T> &lhs, const Blob<T> &rhs) {
    return !(lhs < rhs);
}

template <typename T> bool operator==(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator!=(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator<(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator>(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator<=(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator>=(const BlobPtr<T>&, const BlobPtr<T>&);

// BlobPtr throws an exception on attempts to access a nonexistent element
template <typename T> class BlobPtr {
    friend bool operator==<T>(const BlobPtr<T>&, const BlobPtr<T>&);
    friend bool operator!=<T>(const BlobPtr<T>&, const BlobPtr<T>&);
    friend bool operator< <T>(const BlobPtr<T>&, const BlobPtr<T>&);
    friend bool operator><T>(const BlobPtr<T>&, const BlobPtr<T>&);
    friend bool operator<=<T>(const BlobPtr<T>&, const BlobPtr<T>&);
    friend bool operator>=<T>(const BlobPtr<T>&, const BlobPtr<T>&);
    public:
        BlobPtr(): curr(0) { }
        BlobPtr(const Blob<T> &a, size_t sz = 0): wptr(a.data), curr(sz) { }
        T& operator*() const { 
            auto p = check(curr, "derefernce past end");
            return (*p)[curr]; // (*p) is the vector to which this object points
        }
        BlobPtr& operator++();  // prefix operators
        BlobPtr& operator--();
        T& deref() const;
        BlobPtr<T>& incr(); // prefix version
    private:
        // check returns a shared_ptr to the vector if the check succeeds
        std::shared_ptr<std::vector<T>>
            check(std::size_t, const std::string&) const;
        // store a weak_ptr, which means the underlying vector might be destroyed
        std::weak_ptr<std::vector<T>> wptr;
        std::size_t curr;   // current position within the vector
};

template <typename T> std::shared_ptr<std::vector<T>>
BlobPtr<T>::check(std::size_t i, const std::string &msg) const {
    auto ret = wptr.lock();     // is the vector still around?
    if (!ret)
        throw std::runtime_error("unbound BlobPtr");
    if (i >= ret->size())
        throw std::out_of_range(msg);
    return ret;         // otherwise, return a shared_ptr to the vector
}

template <typename T> BlobPtr<T>& BlobPtr<T>::operator++() {
    // if curr already points past the end of the container, can't increment it
    check(curr, "increment exceeds bounds");
    ++curr;
    return *this;
}

template <typename T> BlobPtr<T>& BlobPtr<T>::operator--() {
    // if curr is zero, decrementing it will yield an invalid subscript
    --curr; // move the current state back one element
    check(curr, "decrement exceeds bounds");
    return *this;
}

template <typename T> T& BlobPtr<T>::deref() const {
    auto p = check(curr, "dereference past end");
    return (*p)[curr];  // (*p) is the vector to which this object points
}

// prefix: return a reference to the incremented object
template <typename T> BlobPtr<T>& BlobPtr<T>::incr() {
    // if curr already points past the end of the container, can't increment it
    check(curr, "increment past end of BlobPtr");
    ++curr;     // advance the current state
    return *this;
}

template <typename T> bool operator==(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs) {
    return lhs.deref() == rhs.deref();
}

template <typename T> bool operator!=(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs) {
    return !(lhs == rhs);
}

template <typename T> bool operator<(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs) {
    return lhs.deref() < rhs.deref();
}

template <typename T> bool operator>(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs) {
    return rhs < lhs;
}

template <typename T> bool operator<=(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs) {
    return !(lhs > rhs);
}

template <typename T> bool operator>=(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs) {
    return !(lhs < rhs);
}


template <typename T> BlobPtr<T> Blob<T>::begin() const {
    return BlobPtr<T>(*this);
}

template <typename T> BlobPtr<T> Blob<T>::end() const {
    return BlobPtr<T>(*this, data->size());
}
#endif

    #include "exercise_16.29.h"
    #include <iostream>
    #include <string>
    #include <vector>
    #include <list>
    
    int main()
    {
        Blob<int> ib{21, 53, 84, 91, 23};
        for (const auto &elem : ib)
            std::cout << elem << ' ';
        std::cout << '\n';
    
        Blob<std::string> sb{"21", "53", "84", "91", "23"};
        for (const auto &elem : sb)
            std::cout << elem << ' ';
        std::cout << '\n';
    
        std::cout << '\n';
        Blob<std::vector<std::string>> vb{ {"21", "5"}, {"53", "23", "42", "23"},
            {"84", "59"}, {"91", "68"}, {"23", "72", "10" } };
        for (const auto &vector : vb) {
            for (const auto &elem : vector)
                std::cout << elem << ' ';
            std::cout << '\n';
        }
    
        int ia[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        std::vector<long> vi = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        std::list<const char*> w = {"now", "is", "the", "time"};
    
        Blob<int> a1(std::begin(ia), std::end(ia));
        Blob<int> s2(vi.cbegin(), vi.cend());
        Blob<std::string> a3(w.cbegin(), w.cend());
    
        return 0;
    }

  • The error is telling you that you have no constructor to convert from `std::stared_ptr` to `my_shared_ptr`, and you are trying to do that in `Blob` constructor. I guess you wanted to use `make_shared` instead of `std::make_shared` there. – Yksisarvinen Jul 29 '20 at 13:00
  • 1
    `make_shared` is broken. It should not take `T`, but `Args...`: `template my_shared_ptr make_shared(Args&&... args) { return my_shared_ptr(new T(std::forward(args)...)); }`. – Evg Jul 29 '20 at 13:01
  • @Evg its not broken, it isn't the same as `std::make_shared` nor as efficient but should work for copyable types. – Alan Birtles Jul 29 '20 at 13:15
  • Please show a [mre] including where you are using `my_shared_ptr` as it could be the source of the error – Alan Birtles Jul 29 '20 at 13:16
  • Are you trying to use `my_shared_ptr` and `std::shared_ptr` at the same time? `data(std::make_shared>(il))` I don't think this is what you wanted to do. – n. m. could be an AI Jul 29 '20 at 13:20
  • By the way, you should also post this at codereview.SE. I can see three memory-corrupting bugs (one of them twice due to copy&paste) on a readthrough. – Sebastian Redl Jul 29 '20 at 14:55
  • As for diagnosing your problem, it's pretty useless if you don't show us the code of the involved types too, i.e. `Blob` and whatever calls `make_shared`. – Sebastian Redl Jul 29 '20 at 14:57
  • @n.'pronouns'm. Unfortunately I'm still seeing the errors even using my own make_shared. Is there something else I'm overlooking? – MasterReDWinD Jul 29 '20 at 15:01
  • @SebastianRedl I've added that to the original post now, thanks. – MasterReDWinD Jul 29 '20 at 15:13
  • Seems your code is accidentally choosing `std::make_shared` through ADL. Rename your own `make_shared` and use the new name and see if that works. – Sebastian Redl Jul 29 '20 at 17:00
  • you still have std::shared_ptr in your BlobPtr. At this point it's simply too much code for an SO question. – n. m. could be an AI Jul 29 '20 at 17:42

1 Answers1

1

The compiler error says that it calls std::make_shared, which returns std::shared_ptr, which you try to pass into my_shared_ptr. my_shared_ptr doesn't have a constructor taking std::shared_ptr.

One easy fix is to call make_shared and not std::make_shared. A better fix is to rename your make_shared into my_make_shared, so that ADL never selects std::make_shared over your make_shared.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • Many thanks for the reply. I added an update to the original post to address the issue of mixing std::make_shared and my_shared_ptr. Unfortunately, using my own implementation of make_shared still results in errors. – MasterReDWinD Jul 29 '20 at 14:54
  • @MasterReDWinD If you look into the error message, which you should, it tells you that it passes `std::shared_ptr` into `my_shared_ptr` because it finds `std::make_shared` through ADL. Rename yours to `my_make_shared`. – Maxim Egorushkin Jul 29 '20 at 14:56
  • I've made the change you suggested. For some reason the std::shared_ptr constructor is still being called: `exercise_16.29.h:58:103: error: no matching function for call to 'my_shared_ptr > >::my_shared_ptr(std::shared_ptr > >)' template Blob::Blob(std::initializer_list il): data(my_make_shared>(il)) { }` – MasterReDWinD Jul 29 '20 at 15:21
  • What does `my_make_shared` return? – Maxim Egorushkin Jul 29 '20 at 15:34
  • The return type is `my_shared_ptr`. – MasterReDWinD Jul 29 '20 at 15:48
  • @MasterReDWinD But the error message still says that `std::shared_ptr` is involved. You need to find where it comes from. – Maxim Egorushkin Jul 29 '20 at 16:27