动态内存分配、指针成员和析构函数

dynamic memory allocation,pointer members and destructors

本文关键字:成员 析构函数 指针 内存 分配 动态      更新时间:2023-10-16

为了理解复制构造函数、复制赋值操作符和析构函数是如何工作的,我编写了以下虚拟类:

#include <string>
#include <iostream>
class Box {
  public:
    // default constructor
    Box(int i=10,const std::string &t=std::string()) : a(i),s(new std::string(t)) {}
    // copy constructor
    Box(const Box &other) { a=other.a; s=new std::string(*other.s); }
    // copy assignment operator
    Box &operator=(const Box &other) { a=other.a; s=new std::string(*other.s); }
    // destructor
    ~Box() { std::cout<<"running destructor num. "<<++counter<<std::endl; }
    int get_int() { return a; }
    std::string &get_string() { return *s; }
  private:
    int a;
    std::string *s;
    static int counter;
};
int Box::counter=0;

我在代码中使用这个类类型来测试它是如何工作的,但我正在考虑销毁具有内置指针类型成员的对象的含义:

#include "Box.h"
using namespace std;
int main()
{
  Box b1;
  Box b2(2,"hello");
  cout<<b1.get_int()<<" "<<b1.get_string()<<endl;
  cout<<b2.get_int()<<" "<<b2.get_string()<<endl;
  Box b3=b1;
  Box b4(b2);  
  cout<<b3.get_int()<<" "<<b3.get_string()<<endl;
  cout<<b4.get_int()<<" "<<b4.get_string()<<endl;
  b1=b4;
  cout<<endl;
  cout<<b1.get_int()<<" "<<b1.get_string()<<endl; 
  {
    Box b5;
  }  // exit local scope,b5 is destroyed but string on the heap
     // pointed to by b5.s is not freed (memory leak)
  cout<<"exiting program"<<endl;
}

该指针在构造函数中初始化,指向自由存储区动态分配的(总是新的)内存。因此,当调用析构函数时,要销毁的对象的成员按相反的顺序销毁。在这种情况下,只有int和指针对象被销毁,并且我最终有内存泄漏(堆上的字符串没有被释放),这是正确的吗?

此外,定义这个复制赋值操作符,每次赋值对象时是否都有内存泄漏(指针指向堆上的新对象,而前者丢失了,不是吗?)?

每次调用new时,都必须删除它(共享指针除外)。

所以必须在析构函数中删除字符串。

赋值操作符作用于一个已存在的实例,因此您已经创建了s,不必为s创建一个新的字符串。

析构函数析构它的成员。由于指针类似于int型,因此只有保存地址的变量被析构,而不是它所指向的对象。

所以,是的,你会有内存泄漏在每个对象中,每次你使用赋值操作符,你设计你的类的方式。

请记住,分配发生在基础构造、复制构造和赋值条件下

在析构函数和赋值时条件释放

需要注意的条件是:

x = x;

因此您的代码可以更改为以下模式(在您无法使用首选适当的智能指针的情况下)

  Box(int i=10,const std::string &t=std::string()) : a(i),s(new std::string(t)) {}
// copy constructor
  Box(const Box &other) { cp(other); }
// copy assignment operator
  Box &operator=(const Box &other) {
    if (&other != this)  // guard against self assignment
    {
       rm();
       cp(other);
    }
    return *this;
  }
// destructor
  ~Box() { rm();  }
private:
  void cp(const Box &other) {a=other.a; s=new std::string(*other.s);
  void rm() {
    std::cout<<"running destructor num. "<<++counter<<std::endl;
    delete s;    // prevents leaks
  }

处理未命名动态分配成员的一种可能方法是每次创建成员时将它们保存在容器中(在对象,函数等中),然后在析构函数中运行for循环,delete语句后跟容器的元素。

你可以用vector:

vector <string*> container;

,你可以这样使用它:

// define it in the private members of your class
vector <string*> container;
// use it when you create the string
container.push_back(new dynamicallyAllocatedObject);
// free memory in the destructor
for(auto it = container.begin(); it != container.end(); ++it) delete *it;