在 std::erase() 之前调用 std::fill() 会产生未定义的行为吗?

Is calling std::fill() before std::erase() produces undefined behaviour?

我正在开发一个 C++11 程序,其中安全性很重要,我的任务是在擦除后将已用内存设置为 0。

我有一个从 int 到 std::vector 指针到 classstd::map 映射。我在 std::map 中有索引和指向我想删除的实例的指针。

下面的代码产生了我想要的输出,但是,我不确定它的格式是否正确(或者我会说我不确定这段代码是否正确)。

我有 2 个问题。

  1. 如果下面的代码没问题,
  2. 只能用-fpermissive编译,编译报错我看不懂
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>


class MyClass
{
    private:
        int num;
    public:
        MyClass(int num) { this->num = num; }
        int GetNum() const { return this->num; }
};


void PrintWorkingData(const std::map<int, std::vector<MyClass*>>& working_data, int idx)
{
    std::cout << "working_data[" << idx << "] is an std::vector, size: " << working_data[idx].size() << ", containing the following items: " << std::endl;
    for (std::vector<MyClass*>::const_iterator it = working_data[idx].begin(); it != working_data[idx].end(); it++)
    {
        std::cout << "(*it)->GetNum() = " << (*it)->GetNum() << std::endl;
    }
}


int main()
{
    MyClass* DeleteMyClass;

    std::map<int, std::vector<MyClass*>> working_data;
    working_data[0].push_back(new MyClass{4});
    working_data[0].push_back(new MyClass{7});
    working_data[1].push_back(new MyClass{11});

    // the origonal code isn't like this; let's suppose
    // we stored in the DeleteMyClass pointer the MyClass pointer
    // that we would like to delete
    working_data[1].push_back(DeleteMyClass = new MyClass{22});

    working_data[1].push_back(new MyClass{33});
    working_data[2].push_back(new MyClass{1000});

    PrintWorkingData(working_data, 0);
    PrintWorkingData(working_data, 1);
    PrintWorkingData(working_data, 2);
    PrintWorkingData(working_data, 3);

    // so our task is to delete DeleteMyClass object from working_data[DeleteItemIndex]
    // and fill with 0 where it was stored
    int DeleteItemIndex = 1;

    std::vector<MyClass*>::iterator pos = std::find(working_data[DeleteItemIndex].begin(), working_data[DeleteItemIndex].end(), DeleteMyClass);
    if (pos == working_data[DeleteItemIndex].end())
    {
        std::cout << "Error: The item does not present in the working_data" << std::endl;
    }
    else
    {
        std::fill(pos, pos + 1, 0);
        working_data[DeleteItemIndex].erase(pos);
        delete DeleteMyClass;
        std::cout << "The object successfully deleted" << std::endl;
    }

    PrintWorkingData(working_data, 0);
    PrintWorkingData(working_data, 1);
    PrintWorkingData(working_data, 2);
    PrintWorkingData(working_data, 3);

    return 0;
}

将指针值设置为 nullptr 不会更改它指向的数据。从向量中删除一个元素将用向量中所有后面的元素覆盖该元素,在分配的内存中(在这种情况下)留下第二个指针(超出向量的大小)到向量中的最后一个元素。

要擦除DeleteMyClass指向的对象所占用的内存,需要分别处理对象销毁和内存释放。这不一定简单或直接,因为可能存在需要解决的细微差别(异常处理、数组与非数组形式)。您还应该记住,可以检查 运行 进程的内存,并在使用它的对象处于活动状态时查看您试图删除的数据。

以下几种方法可能适合您的情况。

一种方法是手动调用析构函数,清除内存,然后释放它。

DeleteMyClass->~MyClass();
memset(DeleteMyClass, 0, sizeof(*DeleteMyClass));
delete (void *) DeleteMyClass;

delete 调用的强制转换是避免调用析构函数所必需的,要清除的字节数使用 DeleteMyClass 类型,如果指向的是 [=33],这将是不正确的=] 来自 MyClass.

另一种方法是使用 placement new 和一个已经分配的内存缓冲区和一个自定义的释放器(在手动调用析构函数之后)来释放内存。

第三种可能性是使用 custom new and delete 函数,可以针对此特定 class 或全局使用。