【发布时间】:2020-11-19 01:49:58
【问题描述】:
我已经编写了 Shared_ptr 的实现,作为阅读 C++ Primer 书籍的一部分。头文件确实编译正确,但是当我尝试将它与“Blob”类一起使用时,我收到了几个“无匹配函数”错误。
我花了几个小时盯着代码,我认为问题出在构造函数上,但是我仍然是 C++ 初学者,没有任何运气来修复它。我之前在代码审查中发布了这个,但被告知这是“离题”,并被指示在此处发布。那里有关 shared_ptr 实现的其他帖子没有帮助。任何能让我朝着正确方向前进的反馈将不胜感激。
注意:我没有发布 Blob 课程,因为它很长,也没有发布测试课程。如果需要,我很乐意提供。
错误示例:
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 实现:
#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
更新:
非常感谢到目前为止的有用回复。使用 std::make_shared 而不是 make_shared 是我进行的调试更改,但是我忽略了 std::make_shared 将返回 std::shared_ptr 而不是 my_shared_ptr 的事实。我在下面添加了原始编译器错误消息,其中 Blob 使用了我的 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> >]':```
根据要求,我现在已经包含了 Blob 类和测试代码:
#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;
}
【问题讨论】:
-
错误告诉您没有构造函数可以从
std::stared_ptr转换为my_shared_ptr,而您正试图在Blob构造函数中执行此操作。我猜你想在那里使用make_shared而不是std::make_shared。 -
make_shared坏了。不应该是T,而是Args...:template<class T, class... Args> my_shared_ptr<T> make_shared(Args&&... args) { return my_shared_ptr<T>(new T(std::forward<Args>(args)...)); }。 -
@Evg 没有损坏,它与
std::make_shared不同,效率也不高,但应该适用于可复制类型。 -
请显示minimal reproducible example,包括您在哪里使用
my_shared_ptr,因为它可能是错误的根源 -
您是否要同时使用
my_shared_ptr和std::shared_ptr?data(std::make_shared<std::vector<T>>(il))我不认为这是你想要做的。
标签: c++ smart-pointers