Mat*_*son 4 c++ pointers object copying dynamic-memory-allocation
#include <iostream>
#include <vector>
#include <cstdlib>
#include <cassert>
struct s_A {
bool bin;
s_A(): bin(0) {}
};
class c_A {
public:
s_A * p_struct;
c_A(): p_struct(NULL) {p_struct = new s_A [16];}
void Reset()
{
delete [] p_struct;
p_struct = new s_A [16];
}
};
int main ()
{
srand(1);
int x = 30;
std::vector <c_A> objects;
objects.assign(x, c_A());
std::vector <c_A> objects_copy;
for(int q=0; q < x; q++)
{
objects_copy.push_back(objects[ rand() % x ]);
objects_copy[q].Reset();
}
for(int q=0; q < 16; q++)
for(int w=0; w < x; w++)
{
// Assertion should not fail, but it does
assert(!objects_copy[w].p_struct[q].bin);
objects_copy[w].p_struct[q].bin = true;
}
}
Run Code Online (Sandbox Code Playgroud)
不知何故,不同复制对象中的指针最终指向同一个内存,并且断言最终失败.如果在未复制的vector上运行,则不会发生这种情况.我认为c_A.Reset()应该释放指针(通过delete [])指向一个新数组,但我显然遗漏了一些东西.
您的问题的具体来源是这些行:
objects_copy.push_back(objects[ rand() % x ]);
objects_copy[q].Reset();
Run Code Online (Sandbox Code Playgroud)
问题在于,当您尝试将对象的副本推入时objects_copy,您最终会在对象中创建对象的浅层副本objects vector.这意味着两个向量中的对象最终将具有彼此复制的指针.因此,当您调用Reset元素时objects_copy vector,会释放仍由objects数组元素指向的内存.
问题是你的c_A班级违反了三级规则.因为您的类封装了资源,所以它需要具有析构函数,复制构造函数和复制赋值运算符.如果您定义了这三个函数,那么当您尝试将对象复制到其中时objects_copy vector,您将能够管理底层资源,可能是通过复制或通过引用计数.有关如何编写这些功能,看看细节这说明了如何编写这些功能.
编辑:这里有一个更详细的描述:
问题是当你向a添加一个对象时vector,你实际上并没有将该对象存储在vector.相反,您正在存储该对象的副本.因此,当您编写时objects_copy.push_back(objects[ rand() % x ]);,您不会在两者中存储相同的对象vectors.相反,您正在创建一个对象的副本objects并将其存储在其中objects_copy.由于您的c_A类型没有定义复制函数,因此最终会生成对象的浅表副本,从而创建指针的副本.这意味着如果您考虑objects列表中的原始对象及其相应的副本objects_copy,它们将分别具有相同p_struct指针的副本.当你调用Reset对象中的对象时objects_copy vector,释放其指针所指向的内存.但是,您没有更新存储在其中的原始对象的指针objects,因此指针现在引用了垃圾内存.尝试使用该指针会导致未定义的行为,从而导致崩溃.
添加复制功能将通过允许您控制复制的方式来解决此问题.如果为其定义复制函数c_A导致复制指向原始指向的对象的新副本,则不会发生此问题,因为每个对象都有自己的单独指针.或者,如果您使用引用计数,那么如果您知道某个其他对象指向它,则可以通过不删除资源来避免此问题.
希望这可以帮助!