在C ++中使用析构函数的一堆不清楚的东西

时间:2012-03-22 00:13:11

标签: c++ pointers destructor

我在C ++中编写了一些非常简单的代码来对向量进行一些简单的操作。这是文件vector.h的内容:

#ifndef VECTOR_H_INCLUDED
#define VECTOR_H_INCLUDED

class Vector {
    int *coordinates;
    int *size;
public:
    Vector(int vector_size);
    Vector(int*,int);
    ~Vector();
    void print(void);
    Vector operator +(Vector);
};
#endif

这是实现(file:vector.cpp):

#include "vector.h"
#include <iostream>
using namespace std;

Vector::Vector(int vector_size) {
    coordinates = new int[vector_size];
    size = new int;
    *size = vector_size;
}

Vector::Vector(int* vector_coordinates, int vector_size){
    coordinates = vector_coordinates;
    size = new int;
    *size = vector_size;
}

void Vector::print(void){
    cout << "[";
    for (unsigned short int index =0; index<*size; index++){
        cout << coordinates[index];
        if (index < *size-1){cout << ", ";};
    }
    cout << "]\n";
}

Vector Vector::operator+ (Vector other) {
  Vector temp(*(other.size));
  if ((*temp.size)!=(*(this->size))){
      throw 100;
  }
  int* temp_c = new int[*(other.size)];
  int* other_c = other.coordinates;
  for (unsigned short int index =0; index<*size; index++){
    temp_c[index] = coordinates[index] + other_c[index];
  }
  temp.coordinates = temp_c;
  return (temp);
}

Vector::~Vector(){
    delete[] coordinates;
    delete size;
}

从我的main.cpp中,我执行以下操作:

#include <iostream>
using namespace std;
#include "vector/vector.h"

const int size = 3;

int main() {
    int *xxx = new int[size];
    xxx[0]=4; xxx[1]=5; xxx[2]=-6;


    Vector v(xxx,size);// v = [4, 5, -6]
    Vector w(size);// w is a vector of size 3

    w = v+v; // w should be w=[8,10,-12]
    w.print();
    return 0;
}

结果是:

[148836464,5,-6,17,148836384,0,0,17,0,0,0,17,3,0,0,17,0,0,0,17,148836480,0,0 ,17,0,10,-12,135025,0,0,0,0,0,0,0,0,分段错误

如果我从析构函数中删除两行:

delete[] coordinates;
delete size;

一切都按预期工作,程序输出:

[8, 10, -12]

我很感激任何解释......

更新1:我将操作符+方法更改为以下内容,但问题未解决:

Vector Vector::operator+(Vector other) {
    int size_of_other = *(other.size);
    int size_of_me = *(this->size);
    if (size_of_other != size_of_me) {
        throw 100;
    }
    int* temp_c = new int[size_of_me];
    int* other_c = other.coordinates;
    for (unsigned short int index = 0; index < size_of_me; index++) {
        temp_c[index] = coordinates[index] + other_c[index];
    }
    Vector temp(temp_c,size_of_me);
    return (temp);
}

更新2:我注意到使用了运营商:

Vector Vector::operator+(Vector other);

我不会得到理想的结果。使其有效的修改是:

const Vector& Vector::operator+(const Vector& other) {
    Vector temp(other.size);
    for (unsigned short int index = 0; index < size; index++) {
        cout << "("<< index <<") "<<coordinates[index] << "+"
                        <<other.coordinates[index] << ", "<< endl;
        temp.coordinates[index] = coordinates[index] + other.coordinates[index];
    }
    return (temp);
}

更新3:更新#2后,我收到编译器的警告,我返回本地'temp'。我将我的代码更改为以下内容,完全解决了所有问题并且工作正常(我返回了一个 copy 的temp):

const Vector Vector::operator+(const Vector& other) const{
    Vector temp(other.size);
    for (unsigned short int index = 0; index < size; index++) {
        temp.coordinates[index] = coordinates[index] + other.coordinates[index];
    }
    return *(new Vector(temp));
}

5 个答案:

答案 0 :(得分:3)

您的Vector::operator+至少有一个错误:

int* temp_c = new int;
...
    temp_c[index] =

当您使用一个整数分配时,您正在为temp_c编制索引。所以你的循环会踩到其他内存,造成不确定的行为。

您还需要定义复制构造函数,以便正确使用Vector个对象。编译器生成默认的复制构造函数,但默认的复制构造函数通常不适用于包含指针的对象。

这一行:

temp.coordinates = temp_c;

导致内存泄漏,因为它会覆盖先前分配的temp.coordinates向量。

更新3 :您的代码

return *(new Vector(temp));

虽然它似乎工作,但仍然是内存泄漏。您正在分配新的Vector,然后编译器调用复制构造函数将其复制到函数的返回值中。没有人delete你刚刚创建的Vector对象,所以存在内存泄漏。

解决方案是编写复制构造函数,而不是依赖于编译器生成的默认复制构造函数。你问题的所有其他答案都说了同样的话。您需要为正确的程序执行此操作。

答案 1 :(得分:2)

您的类需要复制构造函数和复制赋值运算符才能正常工作。他们需要的一个重要暗示是析构函数不是{}。请参阅“Rule of Three”。

为了更好,更现代,您还可以考虑移动构造函数和移动赋值运算符。

答案 2 :(得分:2)

请尝试以下代码:

  1. 实现默认构造函数。无论你的对象是如何构建的,你的内部变量都将指向堆上的某些内容或NULL,因此任何delete []调用都不会死得很厉害。
  2. 实现复制构造函数。默认的拷贝构造函数不会复制堆上的内存,因此这对您来说是一个严重的问题。
  3. 实现赋值运算符。这又避免了浅拷贝。
  4. 删除大小作为指针;在大多数系统中,指针的大小与整数相同,因此使大小成为指针只会使事情变得不必要地复杂化。
  5. 通过避免中间分配来修复添加构造函数。你有一个临时的局部变量,所以使用它而不是分配几个额外的中间对象。
  6. ...看看:

    // VectorImplementation.cpp : Defines the entry point for the console application.
    //
    
    #include <iostream>
    using namespace std;
    
    
    class Vector {
        int *coordinates;
        int size;
    
    public:
        Vector();
        Vector(int vector_size);
        Vector(int*,int);
        Vector(const Vector& v);
    
        ~Vector();
    
        Vector operator +(Vector);
        Vector& operator =(const Vector & other);
    
        void print(void);
    };
    
    Vector::Vector() {
        coordinates = NULL;
        size = NULL;
    }
    
    Vector::Vector(int vector_size) {
        coordinates = new int[vector_size];
        size = vector_size;
    }
    
    Vector::Vector(int* vector_coordinates, int vector_size){
        coordinates = vector_coordinates;
        size = vector_size;
    }
    
    Vector::Vector(const Vector& v) {
        size = v.size;
        coordinates = new int[size];
        memcpy(coordinates,v.coordinates, sizeof(int)*size);
    }
    
    void Vector::print(void){
        cout << "[";
        for (unsigned short int index =0; index<size; index++){
            cout << coordinates[index];
            if (index < size-1){cout << ", ";};
        }
        cout << "]\n";
    }
    
    Vector Vector::operator+ (Vector other) {
      Vector temp(other.size);
      for (unsigned short int index =0; index<size; index++){
          temp.coordinates[index] = coordinates[index] + other.coordinates[index];
      }
      return (temp);
    }
    
    Vector & Vector::operator= (const Vector & other)
    {
      if (this != &other) // protect against invalid self-assignment
      {
        // 1: allocate new memory and copy the elements
        int * tmp_coordinates = new int[other.size];
        memcpy(tmp_coordinates, other.coordinates, sizeof(int)*other.size);
    
        // 2: deallocate old memory
        delete [] coordinates;
    
        // 3: assign the new memory to the object
        coordinates = tmp_coordinates;
        size = other.size;
      }
      // by convention, always return *this
      return *this;
    }
    
    Vector::~Vector(){
        printf("Destructing %p\n", this);
        delete[] coordinates;
    }
    
    const int size = 3;
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    
        int *xxx = new int[size];
        xxx[0]=4; 
        xxx[1]=5; 
        xxx[2]=-6;
    
        Vector v(xxx,size);// v = [4, 5, -6]
        Vector w(size);// w is a vector of size 3
    
        w = v+v; // w should be w=[8,10,-12]
        w.print();
    
        return 0;
    }
    

答案 3 :(得分:0)

这样做是个坏主意:

Vector::Vector(int* vector_coordinates, int vector_size){
    coordinates = vector_coordinates;
    size = new int;
    *size = vector_size;
}

将坐标指针指定给未分配的数据,然后尝试在析构函数中删除它。

但是你得到段错误的真正原因是你使用默认的复制构造函数,而v的临时副本会在向量死亡时删除它。您必须实现复制构造函数并确保深度复制或引用计数。

尝试这样的事情:

Vector::Vector(const Vector& other){
    size = new int(*other.size);
    coordinates = new int[size];
    memcpy(coordinates, other.coordinates, sizeof(int)*(*size));
}

此外,如果将const引用作为参数,则运算符+会更有效:

 Vector Vector::operator+ (const Vector& other)

答案 4 :(得分:0)

考虑一下

w = v+v; // w should be w=[8,10,-12]

为v + v的结果构造临时对象,然后将其分配给w并销毁。 由于您没有和赋值运算符,默认实现执行浅拷贝,并且您正在使用释放的内存。

解决此问题的简单方法是在为成员分配内存时实现复制构造函数/赋值运算符和析构函数。