#include #include #in...">

C ++, "binding" element pointers in multiple objects copied from the same source object

#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; } } 

Be that as it may, pointers in different copied objects point to the same memory, and this statement ultimately fails. This behavior does not happen if you run on an un copied vector.I thought that c_A.Reset () should free the pointers (via delete []) to point to a new array, but I obviously missed something.

+4
source share
1 answer

The following lines are a private source of your problem:

 objects_copy.push_back(objects[ rand() % x ]); objects_copy[q].Reset(); 

The problem is that when you try to click copies of objects on objects_copy , you make a shallow copy of objects in objects vector . This means that objects in two vectors will have pointers that are copies of each other. Therefore, when you call Reset on objects_copy vector elements, you free the memory that the elements of the objects array are still pointing to.

The problem is that your c_A class breaks the rule of three options . Since your class encapsulates a resource, it must have a destructor, copy constructor, and copy assignment operator. If you define these three functions, then when you try to copy objects into objects_copy vector you will have the opportunity to manage the underlying resource, possibly by duplicating or counting links. For more information on how to write these functions, see this description on how to write these functions.

EDIT : Here's a more detailed description of what is going on:

The problem is that when you add an object to vector , you are not actually storing this object in vector . Rather, you keep a copy of this object. That way when you write objects_copy.push_back(objects[ rand() % x ]); , you do not save the same object as in vectors . Instead, you create a copy of one of the objects from objects and save it in objects_copy . Since your c_A type c_A not have specific copy functions, this ends up making a shallow copy of the object, which creates a copy of the pointer. This means that if you think about the original object from the objects list and its corresponding copy in objects_copy , each of them will have a copy of the same p_struct pointer. When you call Reset on an object in objects_copy vector , you free the memory pointed to by the pointer. However, you did not update the pointer of the original object stored in objects , and now the pointer now refers to garbage memory. Attempting to use this pointer leads to undefined behavior, hence, to failure.

Adding copy features fixes this, letting you control how copying is done. If you define a copy function for c_A that causes the copy to point to a new copy of the object that the original points to, this problem will not occur because each object will have its own separate pointer. Alternatively, if you use reference counting, you can avoid the problem by not deleting the resource if you know that it has other objects.

Hope this helps!

+5
source

All Articles