代码之家  ›  专栏  ›  技术社区  ›  Nick X Tsui

当使用带有std::map()[复制]的智能指针时,调用隐式删除的复制构造函数

  •  0
  • Nick X Tsui  · 技术社区  · 10 月前

    我试图将类对象植入到std::map中,但出现了错误。以下是代码:

    hpp类

    #ifndef CLASSMETHODNOTCALLED_CLASSES_HPP
    #define CLASSMETHODNOTCALLED_CLASSES_HPP
    
    #include "iostream"
    #include "memory"
    
    // tow classes with one pointing to the other
    
    class Ca
    {
        int m_va = 5;
    public:
        Ca();
        int getVa();
    };
    
    
    class Cb
    {
        std::unique_ptr<Ca> m_x; // a smart ptr pointing to class Ca
        int m_vb;
    public:
        explicit Cb(int n);
        ~Cb();
        int getCa();
    };
    #endif //CLASSMETHODNOTCALLED_CLASSES_HPP
    

    classes.cpp

    #include "../include/classes.hpp"
    #include "memory"
    
    // Ca
    Ca::Ca()
    {
    
    }
    
    int Ca::getVa()
    {
        return m_va;
    };
    
    // Cb
    Cb::Cb(int n)
    {
        m_x = std::make_unique<Ca>();
        m_vb = n;
    }
    
    Cb::~Cb()
    {
    }
    
    int Cb::getCa()
    {
        return m_x->getVa() + m_vb; // returns 5 + 1 = 6 if works properly
    }
    

    main.cpp

    #include <iostream>
    #include "include/classes.hpp"
    #include "map"
    
    int main()
    {
        Cb cb(1);  // instanciate Cb
    
        std::map<int, Cb> m;
        m.emplace(1, cb); // the line where it complains: Call to implicitly deleted copy constructor
        int i = m.at(1).getCa(); // should return 6 if working properly
    
    //    int i = cb.getCa(); // code without using std::map() works
    
        std::cout << "va = " << i << std::endl;
    }
    

    我认为这是由于智能指针的构造函数被显式删除造成的。我的问题是,如何插入 cb 进入a std::map() 在这种情况下?非常感谢。

    更新:

    现在我正试图从地图中获取一个Cb对象,这是我所做的

    int main()
    {
        Cb cb(1);  // instanciate Cb
    
        std::map<int, Cb> m;
        m.emplace(1, std::move(cb));
    
        Cb ccb = m.at(1); // error occurs here complaining Call to implicitly deleted copy constructor
        int i = m.at(1).getCa();
    
    //    int i = cb.getCa();
    
        std::cout << "va = " << i << std::endl;
    }
    

    知道吗?

    2 回复  |  直到 10 月前
        1
  •  2
  •   463035818_is_not_an_ai    10 月前

    emplace 获取参数并将其转发给映射元素的构造器。如果你通过它a Cb 它会复制它,如果你传递一个右值ref,它会移动它,如果传递一个 1 它将使用它来构建 Cb .

    因此,你可以

    • 向添加移动构造函数 Cb ( Cb(Cb&&)=default; 或者更确切地说,删除析构函数,然后编译器可以生成两者)并执行

      m.emplace(1,std::move(cb));
      
    • 或构建 Cb 到位

      m.emplace(1,1);
      

    但你不能问 安置就位 复制a Cb 因为 Cb 没有复制构造函数。

        2
  •  -1
  •   DatGeoudon    10 月前

    std::unique_ptr 可以移动,但不能复制。

    首先,创建一个移动构造函数/运算符。

    class Cb
    {
        std::unique_ptr<Ca> m_x; // a smart ptr pointing to class Ca
        int m_vb;
    public:
        explicit Cb(int n);
        Cb(Cb&& other) {
            *this = std::move(other);
        }
        Cb& operator=(Cb&& other) {
            m_vb = other.m_vb;
            m_x = std::move(other.m_x);
            return this;
        }
        ~Cb();
        int getCa();
    };
    

    现在你可以移动你的 Cb :

    m.emplace(1, std::move(cb));
    

    请注意 m_x Cb 您从中移动的实例将无效。