在 std::erase() 之前调用 std::fill() 会产生未定义的行为吗?
Is calling std::fill() before std::erase() produces undefined behaviour?
我正在开发一个 C++11 程序,其中安全性很重要,我的任务是在擦除后将已用内存设置为 0。
我有一个从 int 到 std::vector
的 指针到 class 的 std::map
映射。我在 std::map
中有索引和指向我想删除的实例的指针。
下面的代码产生了我想要的输出,但是,我不确定它的格式是否正确(或者我会说我不确定这段代码是否正确)。
我有 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 或全局使用。
我正在开发一个 C++11 程序,其中安全性很重要,我的任务是在擦除后将已用内存设置为 0。
我有一个从 int 到 std::vector
的 指针到 class 的 std::map
映射。我在 std::map
中有索引和指向我想删除的实例的指针。
下面的代码产生了我想要的输出,但是,我不确定它的格式是否正确(或者我会说我不确定这段代码是否正确)。
我有 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 或全局使用。