Valgrind声称内存释放中有太多空闲 我正在阅读Stroustrup的《C++程序设计语言第四版》,并谈到了他谈到析构函数的部分。

Valgrind声称内存释放中有太多空闲 我正在阅读Stroustrup的《C++程序设计语言第四版》,并谈到了他谈到析构函数的部分。,c++,gcc,valgrind,C++,Gcc,Valgrind,我试着跟进这个例子,并检查valgrind是否高兴,但事实并非如此:它声称存在一些错误 我真的不明白它的评论,也不知道问题出在哪里。 我所理解的是valgrind认为有一个额外的空闲,但我没有发现 非常感谢专家们的帮助。谢谢 请注意,我在这个特定示例中使用了try-catch,但我认为这不是问题所在。。。这段代码中真正重要的可能是构造函数和析构函数。然而,为了完整起见,我发布了全部内容 #include <iostream> using namespace std; class Ve

我试着跟进这个例子,并检查valgrind是否高兴,但事实并非如此:它声称存在一些错误

我真的不明白它的评论,也不知道问题出在哪里。 我所理解的是valgrind认为有一个额外的空闲,但我没有发现

非常感谢专家们的帮助。谢谢

请注意,我在这个特定示例中使用了try-catch,但我认为这不是问题所在。。。这段代码中真正重要的可能是构造函数和析构函数。然而,为了完整起见,我发布了全部内容

#include <iostream>
using namespace std;
class Vector
{
public:
    Vector();
    Vector(int s);
    ~Vector();
    double &operator[](int i);
    int size();
    static int get_default_size();

private:
    double *elem;
    int sz;
    static const int default_size = 5;
};

Vector::Vector()
{
    elem = new double[default_size];
    sz = default_size;
    for (int i = 0; i < sz; ++i)
    { //initialize elem array's values
        elem[i] = i;
    }
}

Vector::Vector(int s)
//: elem{new double[s]}, sz{s} //a dangerous idea - what if s is negative?
{
    if (s < 0)
        throw length_error{""};
    elem = new double[s];
    sz = s;
    for (int i = 0; i < sz; ++i)
    { //initialize elem array's values
        elem[i] = 0;
    }
}

Vector::~Vector()
{
    cout << "destructor working now" << endl;
    delete[] elem;
}

double &Vector::operator[](int i)
{
    return elem[i];
}

int Vector::size()
{
    return sz;
}

int Vector::get_default_size()
{
    return default_size;
}

Vector test()
{
    try
    {
        Vector v(-27);
        return v;
    }
    catch (std::length_error)
    {
        cout << "negative length" << endl;
        cout << "length will get default size, " << Vector::get_default_size() << endl;
        Vector v = Vector();
        return v;
    }
}

int main()
{
    Vector v = test();
    for (int i = 0; i < v.size(); ++i)
        cout << v[i] << endl;
}
<pre>==14640== Memcheck, a memory error detector
==14640== Copyright (C) 2002-2017, and GNU GPL&apos;d, by Julian Seward et al.
==14640== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==14640== Command: ./a.out
==14640== 
negative length
length will get default size, 5
destructor working now
==14640== Invalid read of size 8
==14640==    at 0x10933D: main (vector_improved1.cpp:83)
==14640==  Address 0x5b7e190 is 0 bytes inside a block of size 40 free&apos;d
==14640==    at 0x4C3173B: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14640==    by 0x10913A: Vector::~Vector() (vector_improved1.cpp:45)
==14640==    by 0x109299: test() (vector_improved1.cpp:74)
==14640==    by 0x10930E: main (vector_improved1.cpp:81)
==14640==  Block was alloc&apos;d at
==14640==    at 0x4C3089F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14640==    by 0x108FBF: Vector::Vector() (vector_improved1.cpp:21)
==14640==    by 0x10927A: test() (vector_improved1.cpp:74)
==14640==    by 0x10930E: main (vector_improved1.cpp:81)
==14640== 
0
1
2
3
4
destructor working now
==14640== Invalid free() / delete / delete[] / realloc()
==14640==    at 0x4C3173B: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14640==    by 0x10913A: Vector::~Vector() (vector_improved1.cpp:45)
==14640==    by 0x10937B: main (vector_improved1.cpp:81)
==14640==  Address 0x5b7e190 is 0 bytes inside a block of size 40 free&apos;d
==14640==    at 0x4C3173B: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14640==    by 0x10913A: Vector::~Vector() (vector_improved1.cpp:45)
==14640==    by 0x109299: test() (vector_improved1.cpp:74)
==14640==    by 0x10930E: main (vector_improved1.cpp:81)
==14640==  Block was alloc&apos;d at
==14640==    at 0x4C3089F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14640==    by 0x108FBF: Vector::Vector() (vector_improved1.cpp:21)
==14640==    by 0x10927A: test() (vector_improved1.cpp:74)
==14640==    by 0x10930E: main (vector_improved1.cpp:81)
==14640== 
==14640== 
==14640== HEAP SUMMARY:
==14640==     in use at exit: 0 bytes in 0 blocks
==14640==   total heap usage: 4 allocs, 5 frees, 73,912 bytes allocated
==14640== 
==14640== All heap blocks were freed -- no leaks are possible
==14640== 
==14640== For counts of detected and suppressed errors, rerun with: -v
==14640== ERROR SUMMARY: 6 errors from 2 contexts (suppressed: 0 from 0)
#包括
使用名称空间std;
类向量
{
公众:
向量();
向量(int-s);
~Vector();
双重&运算符[](int i);
int size();
静态int get_default_size();
私人:
双*元素;
int sz;
静态常量int默认值_size=5;
};
向量::向量()
{
elem=新的双精度[默认大小];
sz=默认的_大小;
对于(int i=0;icout要解释为什么会发生这种情况,请看一下您的代码的简化版本:

Vector constructor (this=0x7ffee4a777d0)
Vector copy constructor (other=0x7ffee4a777d0 this=0x7ffee4a777d8)
Vector destructor (this=0x7ffee4a777d0)
Vector copy constructor (other=0x7ffee4a777d8 this=0x7ffee4a77810)
Vector destructor (this=0x7ffee4a777d8)
Vector copy constructor (other=0x7ffee4a77810 this=0x7ffee4a77818)
Vector destructor (this=0x7ffee4a77810)
Vector destructor (this=0x7ffee4a77818)
如您所见,最初在
test()
中创建的向量会通过各种实例被复制几次(每个创建的实例也会被销毁)。每当在代码中发生这种情况时,编译器自动生成的默认复制构造函数就会被调用

默认的复制构造函数只是将每个属性从源实例复制到目标实例(包括
double*elem
)。在使用动态分配的内存时,语义通常是错误的,因为多个实例随后“拥有”相同的基础数据。当首先创建的向量被销毁时,它会释放
elem
,使其他实例指向悬空(无效)内存


为了解决这个问题,您需要确保向量实现包含一个赋值和复制构造函数,该构造函数实际分配新内存,并将基础数据从复制的向量复制到目标向量。

您正在复制
向量
并销毁这两个副本(每个
删除
相同的底层数组)。亲爱的@Jon,这是我得到的最好的解释之一。非常感谢您为分解代码及其元素行为所做的努力。我现在了解到幕后有一个默认的复制构造函数(和赋值)我应该重写它。我不知道。谢谢!在实践中,当然可以使用
std::vector
std::unique_ptr
,编译器会自动生成所有适当的特殊成员函数(包括支持移动,但不支持复制后一种情况)。还请注意,许多副本/移动可以被正在优化的编译器消除。@Davidsherring,我现在才看到您的评论。感谢您对编译器优化的进一步解释!
Vector constructor (this=0x7ffee4a777d0)
Vector copy constructor (other=0x7ffee4a777d0 this=0x7ffee4a777d8)
Vector destructor (this=0x7ffee4a777d0)
Vector copy constructor (other=0x7ffee4a777d8 this=0x7ffee4a77810)
Vector destructor (this=0x7ffee4a777d8)
Vector copy constructor (other=0x7ffee4a77810 this=0x7ffee4a77818)
Vector destructor (this=0x7ffee4a77810)
Vector destructor (this=0x7ffee4a77818)