2

我编写了以下虚拟类来了解复制构造函数、复制赋值运算符和析构函数的工作原理:

#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 和指针对象被破坏,我最终会出现内存泄漏(堆上的字符串没有被释放),这对吗?

而且,定义了这个拷贝赋值操作符,我每次赋值对象时是否都会发生内存泄漏(指针指向堆上的一个新对象而前者丢失了不是吗?)?

4

3 回答 3

4

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

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

赋值运算符适用于现有实例,因此您已经创建了 s 并且不必为 s 创建新字符串。

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

所以,是的,你会在每个对象中出现内存泄漏,并且每次你按照设计类的方式使用赋值运算符。

于 2015-09-09T10:57:09.870 回答
2

请记住,分配发生在基础构造、复制构造和令人惊讶的有条件分配上

释放发生在析构函数中,并且有条件地分配

需要注意的条件是:

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
  }
于 2015-09-09T13:50:49.337 回答
0

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

你可以用一个向量来做到这一点:

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;
于 2015-09-09T13:30:03.263 回答