C++复制构造函数:尝试引用已删除的函数

C++ copy constructor: attempting to reference a deleted function

本文关键字:删除 函数 引用 复制 构造函数 C++      更新时间:2023-10-16

我有一个名为classA的类,像这样:

class classA {
    private:        
        char* data; 
    public:
        classA(const classA&) = delete;
        ~classA();      
    };
~classA()
    {
        delete[] data;
    }

在另一个类中,我们称之为classB,我作为成员有一个指向classA的共享指针:

class classB
    {
    private:
        std::shared_ptr<classA> ptrA;
    public: 
        classB(std::shared_ptr<classA>);
    };
classB(std::shared_ptr<classA> sp) : ptrA(sp)
    {}

这是我实例化classB的方式:

classA ca;
classB cb(std::make_shared<classA>(ca));

这给了我以下错误:

尝试引用已删除的函数

显然,我正在尝试引用我定义为deleted的复制构造函数(这是有原因的,不应复制此类的对象(。但是我很困惑为什么调用复制构造函数,因为我正在传递共享指针,以及如何避免这种情况。

您正在调用复制构造函数,尝试创建共享指针。

std::make_shared<classA>(ca)
                         ^^ constructs the classA using these parameters

您可以调用 make_shared<classA>() 来创建指向默认构造classA的共享指针。或者选择另一个构造函数。

这个例子可以简化很多。

#include <memory>
class classA {
 public:
  classA(const classA&) = delete;
  classA() = default;
};

int main() {
  classA ca; // note, no ()
  auto sp = std::make_shared<classA>(ca); // problem.
  auto sp2 = std::make_shared<classA>();  // this does what you want
}

您正在将ca作为参数传递给std::make_shared,它通过使用您传递给make_shared的任何参数调用classA::classA来构造classA

如果您考虑如何实现make_shared,这可能会更明显。

template <typename Cls, typename... Args>
std::shared_ptr<Cls> MakeShared(Args&&... args) {
                                     //this is where the copying happens
  return std::shared_ptr<Cls>{new Cls{std::forward<Args>(args)...}};
}
int main() {
  classA ca;
  auto sp = MakeShared<classA>(ca);
  auto sp2 = MakeShared<classA>();
}

你把ca传递给MakeShared,然后new Cls(...),其中...是你传递给MakeShared的任何内容,在这种情况下,另一个classA对象。

如果以上内容太密集(也许您不习惯forward或可变参数模板(,请考虑这个简化版本的MakeShared,它对您的问题案例执行相同的操作

template <typename Cls, typename Arg>
std::shared_ptr<Cls> MakeShared(const Arg& arg) {
                      // copy here ----+
                      //               v
  return std::shared_ptr<Cls>{new Cls{arg}};
}
int main() {
  classA ca;
  auto sp = MakeShared<classA>(ca);
}