【问题标题】:how to delete a vector that holds other vectors?如何删除包含其他向量的向量?
【发布时间】:2019-02-26 14:59:20
【问题描述】:

我有这个标题代码

    class BaseFile {
private:
    std::string name;

public:
    BaseFile(string name);
    string getName() const;
    void setName(string newName);
    virtual int getSize() = 0;

};

class File : public BaseFile {
private:
    int size;

public:
    File(string name, int size); // Constructor
    int getSize(); // Return the size of the file

};

class Directory : public BaseFile {
private:
    vector<BaseFile*> children;
    Directory *parent;

public:
    Directory(string name, Directory *parent); // Constructor
    virtual ~Directory(); //destructor
    Directory *getParent() const; // Return a pointer to the parent of this directory
    void setParent(Directory *newParent); // Change the parent of this directory
    void addFile(BaseFile* file); // Add the file to children
    void removeFile(string name); // Remove the file with the specified name from children
    void removeFile(BaseFile* file); // Remove the file from children
    void sortByName(); // Sort children by name alphabetically (not recursively)
    void sortBySize(); // Sort children by size (not recursively)
    vector<BaseFile*> getChildren(); // Return children
    int getSize(); // Return the size of the directory (recursively)
    string getAbsolutePath();  //Return the path from the root to this
};

我实现了所有的方法和一个析构函数

Directory::~Directory() {
for (int i = 0; i < children.size(); i++){
    BaseFile *ptr = children[i];
    delete ptr;
}
children.clear();
delete parent;
parent = nullptr;
}

在我的主目录中,我想测试在目录中创建目录 像这样:

int main(int , char **) {
//Environment env;
//env.start();

Directory *d = new Directory("test", nullptr);
Directory *d1 = new Directory("test2" , d);
File *f = new File("test" , 100);

d1->addFile(f);
d->addFile(d1);
delete d;

return 0;
}

当我跑步时

valgrind --leak-check=full --show-reachable=yes Assingment1

由于在向量内创建文件而导致内存泄漏,而该向量位于另一个向量内,因此析构函数无法正确删除它。

==20161== HEAP SUMMARY:
==20161==     in use at exit: 56 bytes in 2 blocks
==20161==   total heap usage: 6 allocs, 4 frees, 72,912 bytes allocated
==20161== 
==20161== 48 bytes in 1 blocks are indirectly lost in loss record 1 of 2
==20161==    at 0x4C3017F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20161==    by 0x10955D: main (Main.cpp:16)
==20161== 
==20161== 56 (8 direct, 48 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==20161==    at 0x4C3017F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20161==    by 0x10D5E9: __gnu_cxx::new_allocator<BaseFile*>::allocate(unsigned long, void const*) (new_allocator.h:111)
==20161==    by 0x10D3F4: std::allocator_traits<std::allocator<BaseFile*> >::allocate(std::allocator<BaseFile*>&, unsigned long) (alloc_traits.h:436)
==20161==    by 0x10D0BF: std::_Vector_base<BaseFile*, std::allocator<BaseFile*> >::_M_allocate(unsigned long) (stl_vector.h:172)
==20161==    by 0x10C8E5: void std::vector<BaseFile*, std::allocator<BaseFile*> >::_M_realloc_insert<BaseFile* const&>(__gnu_cxx::__normal_iterator<BaseFile**, std::vector<BaseFile*, std::allocator<BaseFile*> > >, BaseFile* const&) (vector.tcc:406)
==20161==    by 0x10C335: std::vector<BaseFile*, std::allocator<BaseFile*> >::push_back(BaseFile* const&) (stl_vector.h:948)
==20161==    by 0x10999E: Directory::addFile(BaseFile*) (Files.cpp:42)
==20161==    by 0x10959F: main (Main.cpp:18)
==20161== 
==20161== LEAK SUMMARY:
==20161==    definitely lost: 8 bytes in 1 blocks
==20161==    indirectly lost: 48 bytes in 1 blocks
==20161==      possibly lost: 0 bytes in 0 blocks
==20161==    still reachable: 0 bytes in 0 blocks
==20161==         suppressed: 0 bytes in 0 blocks
==20161== 
==20161== For counts of detected and suppressed errors, rerun with: -v
==20161== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

有没有更好的方法来编写析构函数,以便删除向量中的所有文件?

【问题讨论】:

  • 析构函数对我来说看起来不错,但有些东西我们看不到。你能举一个关于泄漏的最小可验证示例吗?
  • 由于BaseFile 没有虚拟析构函数,此代码引入了未定义的行为。特别是:BaseFile *ptr = children[i]; delete ptr;
  • 停止使用显式的newdelete。使用make_unique()make_shared()
  • 只有我觉得addFile加个子目录很奇怪吗?如果构造函数已经做了同样的事情,为什么还要添加?
  • 另外,C++ 不是 Java。如果有人这样做:File f("test" , 100); d1-&gt;addFile(&amp;f);,那么d1 的析构函数将尝试删除一个没有用new 分配的指针。这似乎是学习设计模式的好时机——可能是工厂模式或类似模式,在这种情况下,客户不从事我所描述的欺骗业务,而是你的班级应该负责创建FileDirectory 对象。

标签: c++ c++11 memory-management memory-leaks valgrind


【解决方案1】:

首先,您的代码似乎不太清楚目录的删除语义。应该清楚一个目录是否删除了它的所有子目录,或者子目录是否删除了它们的父目录。这也需要在复制和移动构造函数/操作符中适当地解决。否则,你会得到泄漏。

此外,您的代码似乎容易多次删除同一目录。这可能会导致崩溃或未定义的行为。

如果您想改进指针处理,有一种很好的方法可以做到这一点,从 C++11 开始就可以使用,称为 智能指针。您可以使用例如 Directory* 这样的原始指针,而不是使用原始指针。 std::shared_ptr&lt;Directory&gt;,它重载了operator-&gt;operator*,所以它的行为就像代码中的指针。

智能指针在很多方面都非常方便。例如,当最后一个实例超出范围时,它们会自动保持引用计数并删除其封装的原始指针。这在可能发生泄漏的异常情况下也很有效。另一个好处是您不必担心低级内存处理,而是有时间专注于应用程序的更大上下文。

如果您是第一次听说智能指针,请知道指针有很多种类型,适用于各种访问和所有权模式。如需更多信息,请查看the introduction&lt;memory&gt; header docs

【讨论】:

    猜你喜欢
    • 2018-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    相关资源
    最近更新 更多