一个更容易的拷贝分配操作符实现

an easier copy-assignment operator implement?

本文关键字:拷贝 分配 操作符 实现 更容易 一个      更新时间:2023-10-16

在C++Primer 5th,13.2.1 class That Acting Like Values中,作者创建了一个类似于值的类,这意味着每个对象都有自己的类管理的资源副本。这个类在下面,它是一个非常简单的类,只包含一个指向字符串的指针,和一个int,member函数只是默认的构造函数和复制控制成员。

class HasPtr{
    public:
    HasPtr(const std::string &s = std::string()) :ps(new std::string(s)), i(0){}
    HasPtr(const HasPtr &p) :ps(new std::string(*p.ps)), i(p.i){}
    HasPtr &operator=(const HasPtr &rhs);
    ~HasPtr(){ delete ps; }
    private:
        std::string *ps;
        int i;
};

下面是操作员的工具=由书籍给出

HasPtr &HasPtr::operator=(const HasPtr &rhs){
    auto newp = new std::string(*rhs.ps);
    delete ps;
    ps = newp;
    i = *rhs.i;
    return *this;
}

这很好,但我认为我们可以使用下面的实现,它可以避免删除指针并分配新的内存。

HasPtr &HasPtr::operator=(const HasPtr &rhs){
    *ps = *rhs.ps;
    i = rhs.i;
    return *this;
}

我测试我的代码是否有效,甚至是自我分配。但是,这个代码有问题吗?

不,您的代码没有问题。

*ps

本身是一个值类型,因此可以直接赋值。如果您正在进行更改以改进代码,您可能需要更进一步,将ps更改为std::string,而不是std::string*。然后,您可以从HasPtr类中消除对new和delete的需要。

如果

*ps

如果是HasPtr类管理的内存的原始指针,则必须编写代码,例如书中的示例。

在您的原始示例中,您已经将*ps的内容复制到了自己,这是可以的。然而,正如您的注释所建议的,情况可能并不总是如此。

至于其他解决方案,这里有一个(也许类似的事情会在你的书后面解释):

#include <algorithm>
//...
HasPtr &HasPtr::operator=(const HasPtr &rhs)
{
    HasPtr temp(rhs);
    std::swap(ps, temp.ps);
    std::swap(i, temp.i);
    return *this;
}

这就是copy/swap习语。从rhs创建一个临时,临时的内部与this的成员交换。最后,临时死亡,带走了this以前的价值观。

请注意,没有显式的内存分配,因为您最初依赖于复制构造函数来创建临时副本。这意味着该技术需要一个可工作的复制构造函数和一个可运行的析构函数。一旦你有了这些,如果这样做,赋值操作符就非常简单了,因为没有真正的"繁重的工作"编码要做——复制构造函数会处理它

那么这比书中的版本容易吗?这取决于你如何看待它——复制/交换几乎可以在任何情况下使用,在这种情况下,你基本上只需要从"3的规则"中描述的三个函数中的两个的工作实现开始,即复制构造函数和析构函数。分配操作员只是利用其他两个功能,再加上执行简单的交换。