我正在编写一个执行差异演化的程序。有一次,我将我的解决方案整理成一个解决方案存档,并遇到了这个问题。我的档案是结构的载体:
std::vector<SingleSolution> archive;
typedef struct SingleSolution
{
int *crop_area;
int *envf;
double nr_cost;
int env_cost;
int front;
int feasible;
} SingleSolution;
当我进行排序并有一个解决方案时,我想将其放入我的存档中,我正在创建一个SingleSolution并将其推送到存档:
SingleSolution member;
member.crop_area = (int *)calloc(crops + 1, sizeof(int));
member.envf = (int *)calloc(M + 1, sizeof(int));
member.front = 1;
member.feasible = feasible[member1];
member.nr_cost = nr_costs[member1];
member.env_cost = env_costs[member1];
for (int n = 1; n <= crops; n++) member.crop_area[n] = solution_crop[member1][n];
for (int n = 1; n <= M; n++) member.envf[n] = solution_env[member1][n];
archive.push_back(member);
//free(member.crop_area);
//free(member.envf);
我在推送到矢量后释放了这些数组,因为我认为它复制了我所推送的内容,但是在打印存档时,我看到了什么是明显的垃圾值,并意识到了原因。所以你可以看到我已经评论过了。 所以我的问题是,push_back究竟发生了什么?它推动阵列开始的内存位置,然后我释放那个空间?我可以用任何方式克服这个问题,或者我需要在main函数中创建空间并在调用sort函数时传递它,然后在完成时释放它?
答案 0 :(得分:2)
当你这样做时:
archive.push_back(member);
您要求它使用复制构造函数将 member
复制到archive
向量的末尾。您可以说&#34; SingleSolution
&#34;中没有复制构造函数,但实际上存在 - 编译器提供的构造函数的浅副本。这是你的问题所在。您正在使用原始指针,默认的复制构造函数只是复制指针的值(它们指向的内存地址 - 缓冲区)。
当您尝试自己管理这些资源时,这是导致未定义行为或内存泄漏的好方法。你意识到当你释放缓冲区但仍然有指针指向旧内存时。
让我们尝试用C ++重写这段代码。
首先,您不需要typedef
。
其次,您的缓冲区可以替换为std::vector
:
struct SingleSolution
{
std::vector<int> crop_area;
std::vector<int> envf;
double nr_cost;
int env_cost;
int front;
int feasible;
};
要填充您的结构,而不必担心内存分配/释放,您可以这样做:
SingleSolution member;
member.crop_area.resize(crops+1);
member.crop_area[0] = 0;
std::copy(&solution_crop[member1][1], &solution_crop[member1][crops+1], member.crop_area.begin()+1);
member.envf.resize(M+1);
member.envf[0] = 0;
std::copy(&solution_env[member1][1], &solution_env[member1][M+1], member.envf.begin()+1);
member.front = 1;
member.feasible = feasible[member1];
member.nr_cost = nr_costs[member1];
member.env_cost = env_costs[member1];
archive.push_back(member);
或者这个:
SingleSolution member;
member.crop_area.reserve(crops+1);
member.crop_area.push_back(0);
std::copy(&solution_crop[member1][1], &solution_crop[member1][crops+1], std::back_inserter(member.crop_area));
// or: std::copy_n(&solution_crop[member1][1], crops, std::back_inserter(member.crop_area));
member.envf.reserve(M+1);
member.envf.push_back(0);
std::copy(&solution_env[member1][1], &solution_env[member1][M+1], std::back_inserter(member.envf));
// or: std::copy_n(&solution_env[member1][1], M, std::back_inserter(member.envf));
member.front = 1;
member.feasible = feasible[member1];
member.nr_cost = nr_costs[member1];
member.env_cost = env_costs[member1];
archive.push_back(member);
答案 1 :(得分:1)
push_back()
将SingleSolution
结构的副本添加到向量的末尾。
现在,该结构恰好包含一些指针。这很好,但是push_back()
并不在意。它没有具体了解这些指针指向的内容。他们可能指向一些静态缓冲区。它们可能指向动态分配的缓冲区(这可能是你的情况),或者它们可能是完全未初始化的指针。
无论情况如何,push_back()
都不关心。它的工作是将给定的结构复制到向量的末尾,以及它的作用。它会复制结构中的任何内容,它不会在副本中分配任何新内容。
如果动态分配一些缓冲区,并将结构中的指针设置为指向那些缓冲区,然后将结构的副本添加到向量中,然后释放这些缓冲区,向量中的结构中的指针将指向释放的缓冲区,指针将不再有效。
因此,当结构的任何实例仍然指向那些缓冲区时,不要释放原始缓冲区。只有在清除vector
后才能释放它们。或者,您可以向结构添加复制构造函数以分配其自己的内存缓冲区副本,并添加析构函数以释放这些复制的缓冲区,然后您可以随时释放原始缓冲区。