创建新结构,插入列表,重新使用指针,return in vector ...是否以及如何删除?

Create new struct, insert into list, re-use pointer, return in vector... whether and how to delete?

在我编写的用于在答案中演示算法的 C++ 代码中,我使用 new 在函数中创建结构,将它们存储在列表中,将它们移动到一个向量,然后返回该向量:

struct my_struct {int a, b, c;};

std::vector<my_struct> myFunction(...) {
    std::list<my_struct> my_list;
    std::list<my_struct>::iterator current = my_list.begin();
    std::vector<my_struct> my_vector;
    my_struct *new_struct = nullptr;

    while (...) {
        ...
        if (!new_struct) {
            new_struct = new my_struct;
            new_struct->a = ...
        }
        ...
        if (new_struct) {
            new_struct->b = ...
            my_list.insert(current, *my_struct);
            my_struct = nullptr;
        }
        ...
        if (...) {
            current->c = ...
            my_vector.push_back(*current);
            current = my_list.erase(current);
        }
        ...
    }
    return my_vector;
}

它可以编译并且似乎可以正常工作,但是我更习惯 JavaScript 并且这段代码感觉像是翻译的 JavaScript;我特别想知道我是否正在造成内存泄漏,以及我是否必须删除调用函数中的结构(以及如何删除)。

是的,您有内存泄漏。如果您调用 new 命令,您将需要在将来调用 delete 命令来释放由 new.

分配的内存

所以,在这个声明中:

my_list.insert(current, *my_struct);

你确实在复制*my_struct的内容,没有得到它的所有权。所以,在下面的语句中:

my_struct = nullptr;

你刚刚发生内存泄漏。

要解决这个问题,请更改您的设计以使用智能指针,例如 unique_ptr,或者更好的是,根本不使用指针,而只使用普通对象:

my_struct new_struct;

正如问题部分中的其他人已经指出的那样,您可能根本不应该使用 new。在那里使用指针的唯一原因是 if(newstruct) 检查,如果它们是您算法的重要组成部分。

但是如果你使用new,你也应该删除。在将结构插入列表或向量后这样做是安全的 - 列表和向量包含副本。

从 C++17 开始,std::optional(在此之前,boost::optional)是针对此处特定问题的明智替代解决方案。它消除了对指针的需要和内存泄漏的危险,但同时仍然为您提供 "nothing" 状态。

你的伪代码会变成这样:

// this is the correct way of defining a struct in C++:
struct my_struct {
    int a;
    int b;
    int c;
};

std::vector<my_struct> myFunction(...) {
    std::list<my_struct> my_list;
    std::list<my_struct>::iterator current = my_list.begin();
    std::vector<my_struct> my_vector;
    std::optional<my_struct> new_struct; // new_struct does not hold a value

    while (...) {
        ...
        if (!new_struct.has_value()) { // if it does not hold a value...
            new_struct = my_struct(); // it holds a value now (a default my_struct)
            new_struct->a = ... // access syntax like a pointer
        }
        ...
        if (new_struct.has_value()) {
            new_struct->b = ...
            my_list.insert(current, *new_struct); // dereference syntax like a pointer
            new_struct.reset(); // it no longer holds a value now
        }
        ...
        if (...) {
            current->c = ...
            my_vector.push_back(*current);
            current = my_list.erase(current);
        }
        ...
    }
    return my_vector;
}

请注意 std::optional 语法 是如何刻意模仿指针的。