C++ C++;设置新对象时是否应销毁对象中的旧对象?

C++ C++;设置新对象时是否应销毁对象中的旧对象?,c++,C++,考虑以下类声明: #include "classB.h" class A { private: B *prop; public: A() { /* does stuff to set up B as a pointer to a new B */ setB(const B& bar) { /* store a copy of B */ // how do I manage the old *prop? *prop = new B(

考虑以下类声明:

#include "classB.h"
class A {
private:
    B *prop;

public:
    A() { /* does stuff to set up B as a pointer to a new B */
    setB(const B& bar) { /* store a copy of B */
        // how do I manage the old *prop?
        *prop = new B(bar);
    }
};

setB()
中,应该如何管理内存分配?我应该删除旧的
*prop
?如果是这样,我是否要取消引用,然后删除?

首先,您必须在构造函数中将
prop
设置为
NULL
,否则,如果尝试
删除它,您将得到未定义的行为

其次,您不需要取消引用,只需分配指针

第三,应该删除析构函数中的内存,这样就不会出现泄漏

最后,如果实现析构函数,还应该有一个复制构造函数和赋值运算符

class A {
private:
    B *prop;

public:
    //set prop to NULL so you don't run into undefined behavior
    //otherwise, it's a dangling pointer
    A() { prop = NULL; }

    //when you set a new B, delete the old one
    setB(const B& bar) { 
        delete prop;
        prop = new B(bar);
    }

    //delete prop in destructor
    ~A() { delete prop; }

    //because you now have a destructor
    //implement the following to obey the rule of three
    A& operator = (const A& other);  //assignment operator
    A(const A& other);               //copy constructor
};

首先,您必须在构造函数中将
prop
设置为
NULL
,否则,如果您试图
删除它,就会得到未定义的行为

其次,您不需要取消引用,只需分配指针

第三,应该删除析构函数中的内存,这样就不会出现泄漏

最后,如果实现析构函数,还应该有一个复制构造函数和赋值运算符

class A {
private:
    B *prop;

public:
    //set prop to NULL so you don't run into undefined behavior
    //otherwise, it's a dangling pointer
    A() { prop = NULL; }

    //when you set a new B, delete the old one
    setB(const B& bar) { 
        delete prop;
        prop = new B(bar);
    }

    //delete prop in destructor
    ~A() { delete prop; }

    //because you now have a destructor
    //implement the following to obey the rule of three
    A& operator = (const A& other);  //assignment operator
    A(const A& other);               //copy constructor
};
如果构造函数总是分配一个新的
B
,您可以将该空间重新用于其他
B
对象的副本

A() { /* does stuff to set up prop as a pointer to a new B */
}

setB(const B& bar) { /* store a copy of B */
    *prop = bar;
}
不要忘记删除析构函数中的
prop

如果构造函数总是分配一个新的
B
,您可以将该空间重新用于其他
B
对象的副本

A() { /* does stuff to set up prop as a pointer to a new B */
}

setB(const B& bar) { /* store a copy of B */
    *prop = bar;
}

不要忘记删除析构函数中的
prop

为了在分配抛出的情况下保持操作前的对象状态,您最好执行如下操作:

void setB(const B& bar)
{
    // Do this first, since it could throw.
    B *newProp = new B(bar);

    // Now delete the old one and replace it with the new one.
    delete prop;
    prop = newProp;
}
请参见此处(特别是关于强异常保证的部分):


为了在分配抛出的情况下保持对象在操作之前的状态,您最好执行如下操作:

void setB(const B& bar)
{
    // Do this first, since it could throw.
    B *newProp = new B(bar);

    // Now delete the old one and replace it with the new one.
    delete prop;
    prop = newProp;
}
请参见此处(特别是关于强异常保证的部分):


谢谢路钦!我有一个复制构造函数和析构函数,我只是懒得把它们指进去。非常好的解释,谢谢!非常感谢。:)我将在接受答案的计时器过期后将其标记为解决方案。编写
a():prop(NULL){}
可能比分配给
prop
更为惯用,但这并不重要。这既不是异常安全的,也不是自分配安全的。(如果你称之为setB(prop),会发生什么情况?)斯图尔特·戈洛德茨(Stuart Golodetz)的单独回答解决了这些问题。(不过,您还需要在这个答案中进行所有其他更改;该更改仅涵盖了setB方法。)谢谢Luchian!我有一个复制构造函数和析构函数,我只是懒得把它们指进去。非常好的解释,谢谢!非常感谢。:)我将在接受答案的计时器过期后将其标记为解决方案。编写
a():prop(NULL){}
可能比分配给
prop
更为惯用,但这并不重要。这既不是异常安全的,也不是自分配安全的。(如果你称之为setB(prop),会发生什么情况?)斯图尔特·戈洛德茨(Stuart Golodetz)的单独回答解决了这些问题。(不过,在这个答案中,您还需要所有其他的更改;这个更改只包括setB方法。)在这种情况下(构造函数总是分配一个新的B),他可能只需要一个对象而不是一个指针,不是吗?这样会更容易,并解决缺少复制构造函数和赋值运算符的潜在问题。当然,除非B可以安全/便宜地进行复制构造,但不进行复制赋值,在这种情况下,这将不起作用……在这种情况下(构造函数总是分配新B的情况下),他可能只需要一个对象而不是指针,否?这将使它更容易,并解决缺少复制构造函数和赋值运算符的潜在问题。当然,除非B可以安全/便宜地进行复制构造,但不进行复制赋值,在这种情况下,这将不起作用…最好的答案是使用唯一的\u ptr,而不是自己尝试。但很明显,对于家庭作业来说,重点可能是教你unique_ptr在做什么,这可能是不合适的。@abarner在重新分配任务时,unique_ptr会自动清理自己吗?谢谢。嗯,unique_ptr上没有赋值运算符。您必须显式地调用reset方法。但是,是的,该方法将自动删除旧值,并且它还处理下面答案中提出的所有其他复杂性。有关详细信息,请参阅。唯一的问题是它需要C++11;如果您必须使用C++03,请转而使用boost::scoped_ptr(灵活性稍差,但只要您不需要额外的灵活性,它也一样好)。最好的答案是使用一个独特的_ptr,而不是自己尝试。但很明显,对于家庭作业来说,重点可能是教你unique_ptr在做什么,这可能是不合适的。@abarner在重新分配任务时,unique_ptr会自动清理自己吗?谢谢。嗯,unique_ptr上没有赋值运算符。您必须显式地调用reset方法。但是,是的,该方法将自动删除旧值,并且它还处理下面答案中提出的所有其他复杂性。有关详细信息,请参阅。唯一的问题是它需要C++11;如果您必须使用C++03,请改用boost::scoped_ptr(灵活性稍差,但只要您不需要额外的灵活性,它就一样好)。