我的Matrix程序出了问题。
有我的错误:
24 bytes in 1 blocks are indirectly lost in loss record 1 of 7
==5334== at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5334== by 0x402B26: Matrix::CountingReference::CountingReference(int, int) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x401725: Matrix::Matrix(int, int) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x401305: main (in /home/detek/Pulpit/Matrix/main)
==5334==
==5334== 24 bytes in 1 blocks are indirectly lost in loss record 2 of 7
==5334== at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5334== by 0x402B26: Matrix::CountingReference::CountingReference(int, int) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x401725: Matrix::Matrix(int, int) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x40187D: Matrix::operator+(Matrix const&) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x40144E: main (in /home/detek/Pulpit/Matrix/main)
==5334==
==5334== 72 bytes in 3 blocks are indirectly lost in loss record 3 of 7
==5334== at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5334== by 0x402B7D: Matrix::CountingReference::CountingReference(int, int) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x401725: Matrix::Matrix(int, int) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x401305: main (in /home/detek/Pulpit/Matrix/main)
==5334==
==5334== 72 bytes in 3 blocks are indirectly lost in loss record 4 of 7
==5334== at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5334== by 0x402B7D: Matrix::CountingReference::CountingReference(int, int) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x401725: Matrix::Matrix(int, int) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x40187D: Matrix::operator+(Matrix const&) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x40144E: main (in /home/detek/Pulpit/Matrix/main)
==5334==
==5334== 120 (24 direct, 96 indirect) bytes in 1 blocks are definitely lost in loss record 5 of 7
==5334== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5334== by 0x401712: Matrix::Matrix(int, int) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x401305: main (in /home/detek/Pulpit/Matrix/main)
==5334==
==5334== 120 (24 direct, 96 indirect) bytes in 1 blocks are definitely lost in loss record 6 of 7
==5334== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5334== by 0x401712: Matrix::Matrix(int, int) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x40187D: Matrix::operator+(Matrix const&) (in /home/detek/Pulpit/Matrix/main)
==5334== by 0x40144E: main (in /home/detek/Pulpit/Matrix/main)
我的代码在这里:
它的Matrix.cpp
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <ctime>
#include "Matrix.h"
using namespace std;
ostream& operator<<(ostream& o,const Matrix& Object)
{
for(int i=0;i<Object.dane->wiersz;i++)
{
for(int j=0;j<Object.dane->kolumna;j++)
{
o<<Object.dane->wsk[i][j]<<" ";
}
o<<endl;
}
return o;
}
Matrix::Matrix()
{
dane=new CountingReference();
}
Matrix::Matrix(int wiersz, int col)
{
dane=new CountingReference(wiersz,col);
}
Matrix::Matrix(const Matrix& Object)
{
Object.dane->countingReference++;
dane=Object.dane;
}
Matrix::~Matrix()
{
if(dane->countingReference==-1)
{
delete dane;
}
}
int Matrix::readref()
{
return this->dane->countingReference;
}
Matrix& Matrix::operator=(const Matrix& Object)
{
Object.dane->countingReference++;
if(dane->countingReference==0)
{
delete dane;
}
dane=Object.dane;
return *this;
}
Matrix Matrix::operator+(const Matrix& Object) throw(string)
{
Matrix A(dane->wiersz,dane->kolumna);
if(dane->wiersz!=Object.dane->wiersz || dane->kolumna!=Object.dane->kolumna)
{
string wyjatek = "Nie sa rowne.";
throw wyjatek;
}
else{
int i,j;
for(i=0; i<dane->wiersz;i++)
{
for(j=0; j<dane->kolumna; j++)
{
A.dane->wsk[i][j]=dane->wsk[i][j]+Object.dane->wsk[i][j];
}
}
}
return A;
}
Matrix Matrix::operator-(const Matrix& Object) throw(string)
{
Matrix A(dane->wiersz,dane->kolumna);
if(dane->wiersz!=Object.dane->wiersz || dane->kolumna!=Object.dane->kolumna)
{
string wyjatek = "Nie sa rowne.";
throw wyjatek;
}
else{
for(int i=0;i<dane->wiersz;i++)
{
for(int j=0;j<dane->kolumna;j++)
{
A.dane->wsk[i][j]=dane->wsk[i][j]-Object.dane->wsk[i][j];
}
}
}
return A;
}
Matrix Matrix::operator*(const Matrix& Object) throw(string)
{
double temp=0;
Matrix A(dane->wiersz,dane->kolumna);
if(dane->kolumna!=Object.dane->wiersz)
{
string wyjatek = "Nie sa rowne";
throw wyjatek;
}
else{
for(int i=0;i<dane->wiersz;i++)
{
for(int j=0;j<Object.dane->kolumna;j++)
{
for(int k=0;k<dane->kolumna;k++)
{
temp+=dane->wsk[i][j]*Object.dane->wsk[j][k];
}
A.dane->wsk[i][j]=temp;
}
}
}
return A;
}
Matrix Matrix::operator+=(const Matrix& Object) throw(string)
{
if(dane->wiersz!=Object.dane->wiersz || dane->kolumna!=Object.dane->kolumna)
{
string wyjatek = "Nie sa rowne.";
throw wyjatek;
}
else{
dane=dane->detach();
for(int i=0;i<dane->wiersz;i++)
{
for(int j=0;j<dane->kolumna;j++)
{
dane->wsk[i][j]+=Object.dane->wsk[i][j];
}
}
}
return *this;
}
Matrix& Matrix::operator-=(const Matrix& Object) throw(string)
{
if(dane->wiersz!=Object.dane->wiersz || dane->kolumna!=Object.dane->kolumna)
{
string wyjatek = "Nie sa rowne.";
throw wyjatek;
}
else{
dane=dane->detach();
for(int i=0;i<dane->wiersz;i++)
{
for(int j=0;j<dane->kolumna;j++)
{
dane->wsk[i][j]-=Object.dane->wsk[i][j];
}
}
}
return *this;
}
Matrix& Matrix::operator*=(const Matrix& Object) throw(string)
{
if(dane->kolumna!=Object.dane->wiersz)
{
string wyjatek = "Nie sa rowne.";
throw wyjatek;
}
else
{
int m=0,n=0;
double temp=0;
m=dane->wiersz;
n=Object.dane->kolumna;
Matrix A(m,n);
for(int i=0;i<dane->wiersz;i++)
{
for(int j=0;j<Object.dane->kolumna;j++)
{
for(int k=0;k<dane->kolumna;k++)
{
temp+=dane->wsk[i][k]*Object.dane->wsk[k][j];
}
A.dane->wsk[i][j] = temp;
temp=0;
}
}
dane=dane->detach();
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
dane->wsk[i][j]=A.dane->wsk[i][j];
}
}
}
return *this;
}
Matrix& Matrix::LoadFromFile(const char *string)
{
int m=0,n=0;
ifstream inFile;
inFile.open(string);
if(inFile.good())
{
inFile>>m;
inFile>>n;
dane=dane->detach();
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
inFile>>dane->wsk[i][j];
}
}
inFile.close();
}
return *this;
}
double Matrix::read( int i, int j) const
{
return dane->wsk[i-1][j-1];
}
void Matrix::write(int i, int j, const double x)
{
dane = dane->detach();
dane->wsk[i-1][j-1] = x;
}
bool Matrix::operator == (const Matrix& Object)
{
int i,j;
for(i=0;i<dane->wiersz;i++)
{
for(j=0;j<dane->kolumna;j++)
{
if(dane->wsk[i][j]!=Object.dane->wsk[i][j])
{
return false;
}
}
}
return true;
}
Matrix& Random(Matrix& Object)
{
for(int i=0;i<Object.dane->wiersz;i++)
{
for(int j=0;j<Object.dane->kolumna;j++)
{
Object.dane->wsk[i][j]=rand()%100+1;
}
}
return Object;
}
Matrix::Mref Matrix::operator()(int i, int j)
{
return Mref(*this,i,j);
}
Matrix::CountingReference::CountingReference()
{
wiersz=0;
kolumna=0;
wsk=NULL;
countingReference=0;
}
Matrix::CountingReference::CountingReference(int wier, int kol)
{
countingReference=0;
wiersz=wier;
kolumna=kol;
wsk=new double*[wier];
for(int i=0;i<wier;i++)
{
wsk[i]=new double[kol];
}
}
Matrix::CountingReference::~CountingReference()
{
for(int i=0;i<wiersz;i++)
{
delete [] wsk[i];
}
delete [] wsk;
wsk=NULL;
}
Matrix::CountingReference *Matrix::CountingReference::detach()
{
CountingReference *pointer;
if(countingReference==0)
{
return this;
}
pointer=new CountingReference(wiersz,kolumna);
for(int i=0;i<wiersz;i++)
{
for(int j=0;j<kolumna;j++)
{
pointer->wsk[i][j]=wsk[i][j];
}
}
countingReference--;
return pointer;
}
Matrix::Mref::operator double() const
{
return s.read(i,k);
}
Matrix::Mref &Matrix::Mref::operator = (double c)
{
s.write(i,k,c);
return *this;
}
Matrix::Mref &Matrix::Mref::operator = (const Mref& ref)
{
return operator= ((double)ref);
}
的main.cpp
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include "Matrix.h"
using namespace std;
int main()
{
Matrix A(3,3);
Matrix B(3,3);
Matrix C(3,3);
Matrix D(3,3);
Matrix F();
Random(B);
Random(C);
Random(D);
cout<<"B: "<<endl<<B<<endl;
cout<<"C: "<<endl<<C<<endl;
cout<<"D: "<<endl<<D<<endl;
cout<<A.readref()<<endl;
A=B+C;
cout<<A.readref()<<endl;
A=B=C=D;
cout<<A.readref()<<endl;
return 0;
}
我知道,在我的析构者的某个地方,我不会释放记忆。但是我已经检查了所有内容,但仍然没有找到问题...我甚至不知道我应该释放哪些指针。你能帮帮我吗?
修改
这是我的Matrix.h
#include <iostream>
#include <cassert>
using namespace std;
class Matrix{
private:
class CountingReference
{
friend class Matrix;
public:
double **wsk;
int wiersz;
int kolumna;
int countingReference;
CountingReference();
CountingReference(int, int);
~CountingReference();
CountingReference* detach();
};
CountingReference *dane;
public:
class Mref
{
friend class Matrix;
Matrix& s;
int i,k;
Mref (Matrix& m, int r, int c): s(m), i(r), k(c) {}
public:
operator double() const;
Mref& operator = (double c);
Mref& operator = (const Mref& ref);
};
friend ostream& operator<<(ostream& o,const Matrix&);
friend ostream& operator<<(const Matrix&, ostream& o);
Matrix();
Matrix(int, int);
Matrix(const Matrix&);
~Matrix();
Matrix& operator=(const Matrix&);
Matrix operator+(const Matrix&) throw(string);
Matrix operator-(const Matrix&) throw(string);
Matrix operator*(const Matrix&) throw(string);
Matrix operator+=(const Matrix&) throw(string);
Matrix& operator-=(const Matrix&) throw(string);
Matrix& operator*=(const Matrix&) throw(string);
bool operator == (const Matrix &);
Matrix& LoadFromFile(const char*);
friend Matrix& Random(Matrix&);
double read(int, int) const;
int readref();
void write(int, int, const double);
Mref operator()(int, int);
friend class CountingReference;
};
答案 0 :(得分:1)
问题的关键:Matrix
析构函数测试dane->countingReference
但不减少它,因此dane->countingReference
永远不会到达被破坏的点。一个dane->countingReference--;
和一个带调试器的步骤来挑选任何一个一个错误将解决这个问题,但是Matrix
和CountingReference
之间的耦合令人不安并且使得这本书保持了很多比实际需要的更难。
一个班级应尽可能少负责,最好是一个。这通常使编写,维护和调试更容易。 Matrix
负责矩阵操作和引用计数以及内存管理,将CountingReference
降级为仅仅容器。
如果Matrix
坚持只做矩阵操作,那么你需要编写和测试的就是矩阵操作。
如果将CountingReference
分解为负责跟踪引用计数和内存管理的紧密相关责任的同等级别,Matrix
可以继续其实际工作:做数学。让我们来看看我们如何做出更聪明的CountingReference
。首先,我们利用基本的C ++概念资源分配是初始化或RAII(What is meant by Resource Acquisition is Initialization (RAII)?)来帮助管理我们的记忆。
class CountingReference
{
private:
int * countingReference;
public:
int wiersz;
int kolumna;
double **wsk;
CountingReference();
CountingReference(int, int);
CountingReference(const CountingReference &);
~CountingReference();
CountingReference& operator=(CountingReference rhs);
};
与原始类似,但请注意countingReference
成员是一个指针,复制和赋值运算符用于观察另一个基本的C ++概念,即三个规则(What is The Rule of Three?)。 countingReference
观察“三规则”允许Matrix
利用The Rule of Zero。现在我们将忽略五法则。
不需要CountingReference* detach();
请注意,这不是线程安全的。如果你试图在没有using <atomic>
的情况下编写这个帖子,那么使这个帖子安全是非常非常讨厌的,如果你使用<atomic>
,你可能会use std::shared_ptr
并且让整个问题消失。
实施:
CountingReference::CountingReference() :
countingReference(new int(1)), wiersz(0), kolumna(0), wsk(NULL)
{
}
CountingReference::CountingReference(int wier, int kol) :
countingReference(new int(1)), wiersz(wier), kolumna(kol), wsk(new double*[wier])
{
for (int i = 0; i < wier; i++)
{
wsk[i] = new double[kol];
}
cout << countingReference << " was created \n";
}
除了使用member initializer list,countingReference
是指针之外,这些构造函数与原始文件类似,而countingReference
从1开始,因为如果引用计数更直观,它们更直观匹配实例数并销毁0上的共享数据。
countingReference
是一个指针,因为共享数据的CountingReference
的所有实例必须具有相同的引用计数器。基本上,不是Matrix
实例共享指向CountingReference
的指针,它们现在都有自己的CountingReference
共享相同的countingReference
。这是RAII开始并为我们节省大量工作的地方。
还要注意一些调试语句,以便我知道我是否在处理坏代码。我可能仍会提供不良代码,但如果是,至少错误并不是愚蠢的。
CountingReference::CountingReference(const CountingReference & src) :
countingReference(src.countingReference), wiersz(src.wiersz), kolumna(src.kolumna), wsk(src.wsk)
{
++(*countingReference);
cout << countingReference << " was copied (" << *countingReference << ")\n";
}
复制构造函数。存储相同的数组并countingReference
作为源,并递增countingReference
以跟踪引用的数量。 “三条规则”的第1部分。
CountingReference::~CountingReference()
{
--(*countingReference);
cout << countingReference << " was decremented (" << *countingReference << ")\n";
if (!*countingReference)
{
cout << countingReference << " was destroyed\n";
for (int i = 0; i < wiersz; i++)
{
delete[] wsk[i];
}
delete[] wsk;
delete countingReference;
}
}
析构。当任何CountingReference
超出范围时,如果递减引用计数并且计数现在为0,则释放数组并countingReference
。这样可以自动完成所有清理工作,从而避免泄漏内存。 “三规则”第2部分。
CountingReference & Matrix::CountingReference::operator=(CountingReference rhs)
{
cout << countingReference << " was replaced by " << rhs.countingReference << "\n";
swap(countingReference, rhs.countingReference);
swap(wsk, rhs.wsk);
swap(wiersz, rhs.wiersz);
swap(kolumna, rhs.kolumna);
return *this;
}
作业运营商。使用Copy and Swap Idiom。这不是执行任务的最有效方式,但它是万无一失的。 “三规则”第3部分。
Matrix
看起来像
class Matrix
{
private:
class CountingReference
{
private:
int * countingReference;
public:
int wiersz;
int kolumna;
double **wsk;
CountingReference();
CountingReference(int, int);
CountingReference(const CountingReference &);
~CountingReference();
CountingReference& operator=(CountingReference rhs);
};
CountingReference dane;
public:
friend ostream& operator<<(ostream& o, const Matrix&);
friend ostream& operator<<(const Matrix&, ostream& o);
Matrix();
Matrix(int, int);
static Matrix clone(const Matrix &);
Matrix operator+(const Matrix &) const;
Matrix operator-(const Matrix &) const;
Matrix operator*(const Matrix &) const;
Matrix operator+=(const Matrix&);
Matrix& operator-=(const Matrix&);
Matrix& operator*=(const Matrix&);
bool operator ==(const Matrix &);
friend Matrix& Random(Matrix&);
};
不需要自定义析构函数,复制构造函数或赋值运算符,因为Matrix没有需要管理的资源(零规则),因此它们留给编译器生成。
我已经放弃了所有的异常说明符(throw(string)
),因为根据我的经验,它们会带来很大的痛苦,但收效甚微。但是,不要相信我,read what Herb Sutter has to say on the topic。他一般都知道他在谈论什么。
函数实现大大简化,因为他们不再需要担心detach
并应用从sbi的优秀What are the basic rules and idioms for operator overloading?中学到的经验教训以及Paul Mackenzie在上述评论中描述的另一个提示我们结束了看起来像这样的功能:
Matrix Matrix::operator+=(const Matrix& Object)
{
if (dane.wiersz != Object.dane.wiersz
|| dane.kolumna != Object.dane.kolumna)
{
string wyjatek = "Nie sa rowne.";
throw wyjatek;
}
else
{
for (int i = 0; i < dane.wiersz; i++)
{
for (int j = 0; j < dane.kolumna; j++)
{
dane.wsk[i][j] += Object.dane.wsk[i][j];
}
}
}
return *this;
}
Matrix Matrix::operator+(const Matrix &Object) const
{
return Matrix.clone(*this) +=Object;
}
我们稍微偏离规范(return Matrix(*this) +=Object;
),因为operator+
不应修改源参数。 Matrix
的复制构造函数导致两个Matrix
s具有相同的引用计数数组,这将允许+=
更改原始文件和副本。这将是坏事。没有人希望x = 10 + 2将10变为12。
clone
看起来像
Matrix Matrix::clone(const Matrix &Object)
{
Matrix result(Object.dane.wiersz,
Object.dane.kolumna);
for (int i = 0; i < result.dane.wiersz; i++)
{
for (int j = 0; j < result.dane.kolumna; j++)
{
result.dane.wsk[i][j] = Object.dane.wsk[i][j];
}
}
return result;
}
Link to complete code and test case.
我没有检查任何与正确管理引用计数数组无关的程序逻辑。所有矩阵操作逻辑都未经检查,可能是虚假的。
不要将其用于生产代码。标准库中有一个非常好的std::shared_ptr
。
答案 1 :(得分:0)
基于Valgrind网站的这个页面: http://valgrind.org/docs/manual/faq.html#faq.deflost 通常“间接丢失”是由于“明确丢失”的错误。
似乎有些情况下您的构造函数不会删除您类的所有字段 当dane-&gt; countingReference!= - 1时会发生什么? 在这种情况下如何删除内部字段? valgrind似乎不喜欢在Counting引用构造函数
之后分配的数据并在operator +:您创建一个新的Matrix对象并按值返回,这意味着您创建了其中的两个,在某些情况下(再次,因为术语:dane-&gt; countingReference == - 1)不要释放他们。