我如何在 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:在大多数情况下,您不需要(或真的不想)像上面显示的那样直接使用 new
或 delete
。在很多情况下,您可以使用 std::shared_ptr
或 std::unique_ptr
代替,使用 std::make_shared
或 std::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) 避免 另一种方法的相对昂贵的删除和新建。
我不是 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:在大多数情况下,您不需要(或真的不想)像上面显示的那样直接使用 new
或 delete
。在很多情况下,您可以使用 std::shared_ptr
或 std::unique_ptr
代替,使用 std::make_shared
或 std::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) 避免 另一种方法的相对昂贵的删除和新建。