我是C ++初学者。我正在使用C ++ Primer(第5版)进行练习。我找到了一个参考 练习13.8来自Github(Here),如下所示。
#include <string>
#include <iostream>
using std::cout;
using std::endl;
class HasPtr {
public:
HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) { }
HasPtr(const HasPtr &hp) : ps(new std::string(*hp.ps)), i(hp.i) { }
HasPtr& operator=(const HasPtr &hp) {
std::string *new_ps = new std::string(*hp.ps);
delete ps; // I don't know why it is needed here?
// But when I delete this line, it also works.
ps = new_ps;
i = hp.i;
return *this;
}
void print() {
cout << *(this->ps) << endl;
cout << this->i << endl;
}
private:
std::string *ps;
int i;
};
int main() {
HasPtr hp1("hello"), hp2("world");
hp1.print();
hp1 = hp2;
cout << "After the assignment:" << endl;
hp1.print();
}
令我困惑的是HasPtr& operator=(const HasPtr &hp)
功能。我不知道为什么这里需要delete ps;
。我认为这是一个错误,但在我编译代码时它起作用了。但是,当我删除delete ps;
行时,它也有效。所以,我不知道是否需要delete ps;
,如果保留它会有什么好处。
答案 0 :(得分:9)
HasPtr::ps
是一个堆分配的std::string
指针。
在所有HasPtr
构造函数中使用new
分配和构造它。因此,当HasPtr::ps
被另一个堆分配的指针替换时,必须使用delete
释放现有内存以避免内存泄漏。
请注意,在现代C ++中,您应该几乎从不使用new
和delete
来管理这样的对象。使用智能指针,例如std::unique_ptr
或std::shared_ptr
,可以安全方便地为您进行内存管理。
我仍然建议您熟悉new
和delete
,因为大量现有代码会使用它们。 cppreference.com
是查找有关该语言的详细信息的好地方。
作为评论中提到的Jan Hudec,将std::string
存储在堆上通常非常愚蠢 - std::string
是堆分配字符数组的包装器,它已经管理为你记忆。
答案 1 :(得分:3)
需要防止内存泄漏:每个new
必须与delete
平衡。
在构造函数中为ps
分配new
的内存。
为new_ps
分配内存并将其分配给ps
时,需要在丢失旧指针值之前释放构造函数分配的内存。
如果省略该行,你的程序确实会“正常工作”,但它会逐渐消耗越来越多的内存,直到最终没有更多的内存。
请注意,您有另一个内存泄漏:您需要创建析构函数,并在其中调用delete ps
。
正如您所看到的,这变得过于复杂。 更好,抛弃所有这些指针并使用std::string s
作为成员变量 - 它会为您处理所有内存管理。
答案 2 :(得分:2)
需要删除以避免内存泄漏。
第ps = new_ps;
行将ps
的地址编辑为指向其他地方。
ps
之前指向的内存仍需要释放。删除此行的效果不会立即显示,程序仍然可以正常工作,但是您有内存泄漏。
EG。
ps = address 0 with value 'f'; new_ps = address 1 with value 'g'
Now let ps = new_ps;
ps = address 1 with value 'g'; new_ps = address 1 with value 'g'
So address 0 is no longer something we can access, but it's not been freed either
答案 3 :(得分:0)
在C ++编程中,自动在类对象上调用 delete 调用类的析构函数。
在一般实践中,析构函数保存代码以释放资源,即文件指针,删除在类中创建的对象。这样,当您在对象上调用 delete 时,它分配的资源被释放,即返回系统
如果没有释放这些资源,为这些资源分配的内存将不会返回给系统。每次调用对象时,都会丢失一定的内存,并且在一段时间内会丢失一大块记忆。这被称为内存泄漏。
因此,当您在对象上调用delete时,如果您在析构函数中执行了这些操作,则确保释放您获取的资源。