如何避免在赋值/返回时销毁对象

时间:2016-02-06 07:16:11

标签: c++

这是一个示例类:

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分配一个果皮并返回一个指针,因为对于一个我喜欢剥离的容易性,一旦它超出范围就会被自动销毁,而且,剥离有一个更好的没有支架操作符必须首先在括号中取消引用果皮。
  3. 赋值操作符是我试图避免删除它但从未调用的东西,不确定我是否正确。

    无论如何,我如何制作自动myPeel = peelSource.getPeel();没有删除数据的工作?

2 个答案:

答案 0 :(得分:1)

你写道:

  

我不想用新的分配果皮并返回一个指针,因为对于我喜欢剥离的容易性,一旦它超出范围就会自动销毁掉,而且,剥离有一个支架操作员,这个很多更好,无需先取消括号中的果皮。

您可以考虑以下内容。首先使用您想要的界面编写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个对象有效地进行值操作。

答案 1 :(得分:0)

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