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

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

我有一个叫做 classA 的 class,像这样:

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

~classA()
    {
        delete[] data;
    }

在另一个 class 中,我们称它为 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));

这给了我以下错误:

attempting to reference a deleted function

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

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

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);
}