我如何在 C++ 中 un-initialize 和 object?

How do I un-initialize an object in C++?

我不是 100% 确定我为这个权利写了标题所以这就是我想要能够做的...

我有一个 class 是这样定义的...

class Animal
{
public:
    Animal() : m_name("New Animal")
    {
    }

    Animal(const std::string& name) : m_name(name)
    {
    }

    Animal(const Animal& animal) : m_name(animal.name)
    {
    }

private:
    const std::string name;
};

然后我像这样初始化这个 class 的 object...

Animal* m_animal = new Animal("Leroy");

在我的程序中的某个时刻,用户将单击一个按钮,这将导致 m_animal 变为空。意思是叫Leroy的宠物不应该存在了..

我以为我可以使用 delete m_animal,但是一旦我调用它,我就不能再使用 m_animal 而不会导致内存分配错误。

所以我想我的问题是... 我使用以下代码是否会导致内存泄漏,因为名为 Leroy 的宠物未被删除......如果是这样,有什么替代方法可以完成此操作?

m_pet = NULL;

整个过程是这样的...

Animal* m_animal = new Animal("Leroy");
Animal* m_animal2 = new Animal("Boo");
std::cout << m_animal.name << endl;
m_animal = NULL;
m_animal = new Animal(m_animal2);
std::cout << m_animal.name << endl;

想使用delete m_animal;。你可以这样做:

std::cout << m_animal.name << endl;
delete m_animal;
m_animal = new Animal(m_animal2);
std::cout << m_animal.name << endl;

调用delete m_animal后,不能再使用m_animal指向的,但肯定可以再次使用m_animal指针.

如果您使用 new 运算符创建对象,则需要使用 delete 运算符删除它。

Animal* animal = new Animal( "Pig" );

// Using the animal ...

delete animal;
animal = nullptr;

您需要使用 new - delete 对来避免内存泄漏。

您可以只添加一个 clear 成员函数(例如)将名称设置为空字符串。这意味着 "Leroy" 不再存在,但存在一个处于有效状态的 Animal,因此您可以用它来容纳其他动物,而无需删除旧动物并分配新动物。

但是,这仍然会留下一个 Animal 对象——只是一个没有名字的对象。如果要将分配与内存中对象的 creation/destruction 分开,可以使用 operator new 分配原始内存,然后使用新放置在该内存中创建对象。当你想销毁对象时,可以直接调用它的析构函数,这将真正销毁对象(但保留分配的内存)。

记忆完成后,您可以使用operator delete删除记忆。

旁白:举个例子,这几乎就是 std::vector 对其内存块所做的事情。虽然在处理多个对象时它可能 更多 有用,但对单个对象执行此操作也没有什么特别错误。

旁白 #2:在大多数情况下,您不需要(或真的不想)像上面显示的那样直接使用 newdelete。在很多情况下,您可以使用 std::shared_ptrstd::unique_ptr 代替,使用 std::make_sharedstd::make_unique 来分配对象。

因为这两个是指向Animal的指针class。这也应该有效:

std::cout << m_animal->name << endl;
m_animal = m_animal2;
std::cout << m_animal->name << endl;

无需为动物第三次分配内存,即使其中一个之前被删除,其代码效率低下。那么你应该只删除这些指针中的一个并将它们都设置为nullptr。不过,使用 std::shared_ptr 可能是更可靠的解决方案。

有时(但不适用于此 mcve),使用 init() 方法更简单。

虽然我更喜欢你在这里使用的初始化列表(在 ctor 之后),但有时你会 运行 进入系统启动序列选项,其中 ctor 参数是 not 尚可用,因此不能由 ctor 填写。当两个或多个实例(相同或不同 class)具有指向另一个实例(如工作和保护硬件控制)

时,这是一个特殊的问题

因此,您可能会考虑以下内容,它通过提供 init() 方法来解决排序和相互依赖的挑战。

class Animal
{
public:
    Animal()
    {
        init("New Animal")
    }

    Animal(const std::string name)
    {
        init(name);
    }

    Animal(const Animal& animal)
    {
        init(animal.m_name); 
    }

    void init(std::string name)
    {
       m_name.erase(); // clear the previous attribute 
       //           (not really needed here, but included for clarity)
       m_name = name;  // fill in new attribute 

       // and continue with both clear (when needed) and init's 
       // of all the other data attributes 
       // in an order similar to the initialization list.
       // note that the compiler won't be able to notify you
       // of out of order initialization issues.
   }

private:
    const std::string name;
};

那么,init() 还有什么用吗?

你问过

how do I un-initialize an object.

在这种情况下,您可以简单地使用 "init(...)" 同时

a) 清除之前的状态信息(必要时)

b) 像新创建的一样初始化状态信息

c) 避免 另一种方法的相对昂贵的删除和新建。