C++ 共享ptr有问题。我无法创建没有错误的结构

C++ 共享ptr有问题。我无法创建没有错误的结构,c++,shared-ptr,C++,Shared Ptr,请帮助查找自定义共享指针类中的错误SharedPtr。我找不到它。但代码可以处理泄漏 我认为重置方法或运算符=方法中存在错误。可能不需要调用这些方法代码就可以工作。我认为是这样,因为瓦尔格林没有泄露和错误。但是调用这些方法会显示错误,有时会泄漏 #include <iostream> #include <algorithm> #include <memory> using std::cout; using std::cin; using std::endl;

请帮助查找自定义共享指针类中的错误
SharedPtr
。我找不到它。但代码可以处理泄漏

我认为重置方法或
运算符=
方法中存在错误。可能不需要调用这些方法代码就可以工作。我认为是这样,因为瓦尔格林没有泄露和错误。但是调用这些方法会显示错误,有时会泄漏

#include <iostream>
#include <algorithm>
#include <memory>

using std::cout;
using std::cin;
using std::endl;

template <typename T>
struct SharedPtr
{
    explicit SharedPtr(T *ptr = 0) : p_(ptr), c_(0)
    {
        if (p_) c_ = new size_t(1);
    }
    ~SharedPtr()
    {
        if (c_ && --*c_ == 0) 
        {
            delete p_; 
            delete c_;
        }
    }
    SharedPtr(const SharedPtr &p) : p_(p.get()), c_(p.getc()) 
    {
        if (c_) { ++*c_; }
    }
    SharedPtr& operator=(const SharedPtr &p)
    {
        p_ = p.p_;
        c_ = p.c_;
        return *this;
    }

    T* get() const { return p_;}
    size_t* getc() const { return c_; }
    size_t getcc() const { return *c_; }

    void reset(T *ptr = 0)
    {
        SharedPtr(ptr).swap(*this);
        // if (c_ && --*c_ == 0) 
        // {
        //     delete p_; 
        //     delete c_;
        // }
        // if (ptr == nullptr)
        // {
        //     c_ = nullptr;
        // }
        // p_ = ptr;
    }

    T& operator*() const { return *p_;}
    T* operator->() const { return p_;}
private:
    void swap(SharedPtr& other)
    {
        std::swap(p_, other.p_);
        size_t* tmp = c_;
        c_ = other.c_;
        other.c_ = tmp;
    }
    T * p_;
    size_t * c_;
};

int main ()
{
    SharedPtr<int> p1(new int(5));
    SharedPtr<int> p2(new int(10));
    SharedPtr<int> p5;
    p5 = p2;
    p1 = p5;
    p1.reset();
}
还有一个同样的错误:

==12777== Invalid read of size 8
==12777==    at 0x1093F9: SharedPtr<int>::~SharedPtr() (in /home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==    by 0x109296: main (in /home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==  Address 0x4da5d70 is 0 bytes inside a block of size 8 free'd
==12777==    at 0x483D1CF: operator delete(void*, unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==12777==    by 0x10944D: SharedPtr<int>::~SharedPtr() (in /home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==    by 0x1094DA: SharedPtr<int>::reset(int*) (in /home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==    by 0x10928A: main (in /home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==  Block was alloc'd at
==12777==    at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==12777==    by 0x1093C0: SharedPtr<int>::SharedPtr(int*) (in /home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==    by 0x109242: main (in /home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==大小为8的无效读取
==12777==at 0x1093F9:SharedPtr::~SharedPtr()(in/home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==by 0x109296:main(in/home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==地址0x4da5d70是大小为8 free'd的块中的0字节
==12777==at 0x483D1CF:运算符删除(void*,无符号长)(在/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so中)
==12777==by 0x10944D:SharedPtr::~SharedPtr()(in/home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==by 0x1094DA:SharedPtr::reset(int*)(in/home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==0x10928A:main(in/home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==在分配块时
==12777==at 0x483BE63:新运算符(无符号长)(in/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==12777==by 0x1093C0:SharedPtr::SharedPtr(int*)(in/home/baseoleph/git/stepik/1_7_CPP/a.out)
==12777==by 0x109242:main(in/home/baseoleph/git/stepik/1_7_CPP/a.out)

您的赋值运算符是否应该减少c_u并可能释放p_u?

并增加新的c_值

问题出在
操作符=
中。您应该释放上一个值(如果有)并增加计数。你应该考虑一个特殊情况,旧的和指定的点对象是相同的

由于您已经有了一个
交换
,因此您应该只使用复制和交换习惯用法,该习惯用法对可能出现的情况非常有效:

SharedPtr& operator=(const SharedPtr &p)
{
    SharedPtr tmp(p);
    swap(tmp)
    return *this;
}

如果
SharedPtr
不包含任何内容,则dtor或临时文件将不起任何作用,如果它包含对象,则dtor将正确地将其递减并选择性地销毁。如果您指定同一个对象,它也不会造成任何伤害…

这只是一个类的定义,它本身不会泄漏。请发布一个和valgrind的输出
SharedPtr& operator=(const SharedPtr &p)
{
    SharedPtr tmp(p);
    swap(tmp)
    return *this;
}