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

时间:2019-05-04 22:57:39

标签: c++ algorithm memory stl fill

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

我有一个std::map,它从int到指向类的指针std::vector 的映射。我在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;
}

1 个答案:

答案 0 :(得分:0)

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

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

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

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

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

为避免调用析构函数,必须对delete进行强制转换,要清除的字节数使用DeleteMyClass类型,如果所指向的是从{{派生的类1}}。

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

第三种可能性是为此特定类或全局使用custom newdelete函数。