代码之家  ›  专栏  ›  技术社区  ›  scx

在unique_ptr内显式调用对象的复制构造函数

  •  1
  • scx  · 技术社区  · 7 年前

    我在使用pimpl成语时使用了 const std::unique_ptr 来保存类实现。我的类需要支持副本构造和副本分配。我要做的是手动调用 impl unique_ptr . 然而,我不明白怎么做。

    #include <memory>
    
    struct potato {
        potato();
        ~potato();
        potato(const potato& p);
    
    private:
        struct impl;
        const std::unique_ptr<impl> _pimpl;
    };
    
    struct potato::impl {
        int carbs = 42;
    };
    
    potato::potato()
            : _pimpl(std::make_unique<impl>()) {
    }
    
    potato::~potato() = default;
    
    potato::potato(const potato& p) {
        // Try to call the copy constructor of impl, stored in unique_ptr, not the
        // unique_ptr copy-constructor (which doesn't exist).
        _pimpl.get()->impl(p._pimpl); // This doesn't work.
    }
    

    我检查了另一个关于显式调用对象上的复制构造函数的问题。一个答案建议使用新的布局。

    Object dstObject;
    new(&dstObject) Object(&anotherObject);
    

    我可以在复制构造函数中使用它吗?如果是,怎么做?我真的不明白那里发生了什么。非常感谢。

    2 回复  |  直到 7 年前
        1
  •  5
  •   Matteo Italia    7 年前

    impl 类内部 unique_ptr

    你的错误就在这里。因为您在的(副本)构造函数中 potato ,没有 恳求 对象,您必须在其上“手动”调用复制构造函数。

    只需构建新的 恳求 向其传递对原文的引用 恳求

    potato::potato(const potato& p)
        : _pimpl(std::make_unique<impl>(*p._pimpl) {
    }
    

    至于作业,你可以很容易地转发到 恳求 分配操作员:

    potato &operator=(const potato &p) {
        *_pimpl = *p._pimpl;
        return *this;
    }
    
        2
  •  0
  •   Davislor    7 年前

    您可以在未初始化的存储上使用placement显式调用构造函数 new 接线员,如你所说。通过显式调用对象的析构函数,可以将对象的存储返回到未初始化状态。

    下面是赋值运算符的一个简单实现,它显式调用已定义为接口一部分的复制构造函数和析构函数:

    #include <new>
    
    potato& potato::operator=(const potato& x)
    {
      if ( this != &x ) { // check for self-assignment!
        this->~potato();
        new(this) potato(x);
      }
    
      return *this;
    }
    

    您可能还希望定义一个move构造函数,并在右侧是临时的情况下重载赋值运算符。也就是说,对于 potato&& src const potato& src . 如果您的类支持swap习惯用法,您可以使用它,或者使用与上面相同的代码,但是调用 new(this) potato(std::move(src)); .

    如果您有权访问封装在智能指针中的类的析构函数和复制构造函数,则可以对它们执行相同的操作,只需取消对智能指针的引用。不过,你可能不想这么做。

    如果类的内容是智能指针、STL容器等,那么默认的复制构造函数和赋值操作符应该可以正常工作。您可能希望通过编写以下内容来复制智能指针引用的数据 *p = x 或 *p = *q std::swap

    推荐文章