如何避免在分配/返回时破坏对象

How to avoid destroying an object on assignment / returning

本文关键字:对象 返回 何避免 分配      更新时间:2023-10-16

这是一个示例类:

struct peel {
    int* p;
    bool nodelete;
    peel() { 
        nodelete = false; 
    }
    ~peel() {
        if (!nodelete) delete p;
    }
    peel& operator=(const peel& other) {
        p = other.p;
        nodelete = true;
    }
};
struct banana {
    peel getPeel() {
        peel ret;
        ret.p = new int();
        return ret;
    }
};

所以当我打电话

banana peelSource;
auto myPeel = peelSource.getPeel();

我无法使用 myPeel,因为在返回和赋值之间的某个地方,peel 对象的析构函数被调用,当指针被复制时,分配的内存消失了,因此指针无效。

为什么我想像这样创建对象:

  1. 在我的实际课堂上,香蕉包含许多对果皮的创建至关重要的信息,总的来说,让香蕉构建果皮更容易。
  2. 我不想分配带有 new 的剥离并返回一个指针,因为对于一个我喜欢剥离一旦超出范围就会自动销毁的便利性,而且 peel 有一个括号运算符,这更好,而不必首先取消引用括号中的剥离。

赋值运算符是我试图避免删除内容,但它从未调用过,不确定我是否做对了。

无论如何,我如何使自动 myPeel = peelSource.getPeel((; 工作而不让它删除数据?

你写道:

我不想分配带有 new 的剥离并返回一个指针,因为对于一个我喜欢剥离一旦超出范围就会自动销毁的便利性,而且 peel 有一个括号运算符,这更好,而不必首先取消引用括号中的剥离。

您可以考虑以下几点。首先使用所需的接口(例如,括号运算符(编写peel。将所有内容保存为常规值成员,不带指针、指示不删除的布尔标志等。

struct peel
{
    /* Hold here everything as regular value members, without 
    pointers or boolean flags indicating whether to delete, and
    so forth.*/
    // Here's your brackets operator.
    ... operator[](...);
};

现在只需使用这个

struct banana
{
    peel getPeel() {
        peel ret;
        ...
        return ret;
    }
};

配置文件以查看使用它是否有任何问题。由于NRVO的原因,很有可能不会有。

如果由于某种原因,您发现无法按值有效地操作peel对象,请考虑按如下方式重构。首先,将所有重部件移动到peel_imp(再次避免指针和布尔标志(。

// "Heavy" peel stuff.
struct peel_imp
{
    /* Hold here everything as regular value members, without 
    pointers or boolean flags indicating whether to delete, and
    so forth.*/
};

然后,正如@EdHeal注释中所建议的那样,使用智能指针来保存实现。

struct peel
{
    ... operator[](...);
    std::shared_ptr<peel_imp> m_imp;
};

再次使peel对象对值操作有效。

为什么要在分配时销毁对象并返回。它将是无效的指针并且无用。更好的选择是使用移动构造函数/移动赋值运算符。