This may a stupid question, but I'm gonna ask it anyway:
Suppose you have a pointer: Object* pointer which points at a dynamically allocated object.
class PointClass
{
Array<Object*> m_array1;
Array<Object*> m_array2;
void Delete1()
{
for (int i = 0; i < m_array1.Length; i++)
{
delete m_array1[i];
}
}
void Delete2()
{
for (int i = 0; i < m_array2.Length; i++)
{
delete m_array2[i];
}
}
}
Now, you put your pointer both in m_array1 and in m_array2.
When you try to delete the arrays, in one of them you will have a pointer which points to a deallocated space, so you can't delete it again!
I can't just assign the pointers NULL after the deletion because it wouldn't affect the pointer in the other array.
How would you solve it?
Well the simplest way would be to use a reference-counting pointer, like those available in boost::smart_ptrs.
Otherwise, you need to assign owners to the pointers - you need to decide which class will be responsible for allocating/deleting that particular pointer. If for some reason you decide that should be this class, then you could remove the duplicates from the arrays by adding all the pointers to a set before enumerating them.
If you have to share pointers in this way, something like a ref counted pointer may work well.
See this site which gives an exposé of various 'smart-pointer' techniques.
Smart Pointers
My initial answer is: Don't do that.
If you absolutely have to for some reason, you could wrap it in a smart pointer
Best solved is not passing the same pointer to both arrays. :P If you really need to, and you also need to reflect that change to all other "same" pointers, a pointer-to-pointer will do.
#include <iostream>
struct Object{};
int main(){
Object* ptr = new Object;
Object** ptrptr = &ptr;
delete *ptrptr;
*ptrptr = 0;
// both print 0
std::cout << *ptrptr << std::endl;
std::cout << ptr << std::endl;
}
On Ideone.
Another way is with a reference-to-pointer.
int main(){
Object* ptr = new Object;
Object*& refptr = ptr;
delete refptr;
refptr = 0;
// both print 0
std::cout << refptr << std::endl;
std::cout << ptr << std::endl;
}
But the second best way is probably a ref-counted smart pointer.
How would you solve it?
By not storing the same pointer in two different places. Doing this creates a duplication of data, and confuses ownership semantics. Who owns the memory pointed to by pointer? Ownership is not clear.
Under normal circumstances, dynamically allocated objects should be owned by the same module that allocated it, and only that module will have direct access to the objects or delete the memory. That's not to say other modules can't get at the data.
As others have suggested use smart pointers to solve your problem. If you have to solve it by writing your own code, I would make each of the delete function also search the "other" array to delete all pointers in the first array that can be found in the other array. And it is a last option option as this would not be my first solution to implement anything as your approach
void Delete2()
{
for (int i = 0; i < m_array2.Length; i++)
{
for (int j = 0; j < m_array1.Length; j++)
{
if (m_array2[i] == m_array1[j])
{
delete m_array1[j]
m_array1[j] = NULL;
}
delete m_array2[i];
m_array2[i] = NULL;
}
}
Then look for ways to optimise it
If I understood your question, you have the same (valid) pointer stored in 2 different arrays.
The problem is that after you delete it on array1, you can't do it again in the second array.
One way to do this is change your array definition to store the memory address of the pointer itself, instead of storing the address of the allocated memory:
const int array_size = 3;
int** m_array1[array_size];
int** m_array2[array_size];
and the rest of the code could be implemented as:
void Delete1()
{
for (int i = 0; i < array_size - 1; i++) // delete all memory but leave the last intact
{
if (*(int*)m_array1[i])
{
cout << "Delete1: erasing #" << i << " with mem addr " << std::hex << *m_array1[i] << std::dec << endl;
delete *m_array1[i];
*m_array1[i] = NULL;
}
}
}
void Delete2()
{
for (int i = 0; i < array_size; i++)
{
if (*m_array2[i])
{
cout << "Delete2: erasing #" << i << " with mem addr " << std::hex << *m_array2[i] << std::dec << endl;
delete *m_array2[i];
*m_array2[i] = NULL;
}
else
{
cout << "Delete2: !!! memory at #" << i << " was already deleted." << endl;
}
}
}
int main()
{
int* num1 = new int(10);
int* num2 = new int(20);
int* num3 = new int(30);
cout << "main: storing " << std::hex << &num1 << " which points to " << num1 << std::dec << endl;
cout << "main: storing " << std::hex << &num2 << " which points to " << num2 << std::dec << endl;
cout << "main: storing " << std::hex << &num3 << " which points to " << num3 << std::dec << endl;
m_array1[0] = &num1;
m_array1[1] = &num2;
m_array1[2] = &num3;
m_array2[0] = &num1;
m_array2[1] = &num2;
m_array2[2] = &num3;
Delete1();
Delete2();
}
Outputs:
main: storing 0xbfc3818c which points to 0x87b6008
main: storing 0xbfc38188 which points to 0x87b6018
main: storing 0xbfc38184 which points to 0x87b6028
Delete1: erasing #0 with mem addr 0x87b6008
Delete1: erasing #1 with mem addr 0x87b6018
Delete2: !!! memory at #0 was already deleted.
Delete2: !!! memory at #1 was already deleted.
Delete2: erasing #2 with mem addr 0x87b6028
Related
I am trying to figure out where to place the delete pointerstatement in the program below. I want to clear the memory space that pointer is pointing to in order to avoid memory leaks. It seems that no matter where I put it, I get an error stating:
main(8282,0x7fff95d823c0) malloc: *** error for object 0x7fff582d3960: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
I am not sure how to fix this. Any help is appreciated.
full code:
#include <iostream>
#include <vector>
using namespace std;
int main() {
//initialize vector
vector<int> historyValues;
//initialize pointer and int variable
int *pointer;
pointer = new int;
pointer = 0;
int currentValue;
//make pointer point to the address of currentValue
pointer = ¤tValue;
//increment pointer by 1 for a total of 10 times.
//since pointer is pointing at currentValue, currentValue should change also.
//push back the current value of currentValue into the vector.
for (int i = 0; i < 10; i++) {
*pointer += 1;
historyValues.push_back(currentValue);
}
//print final results
cout << "currentValue: " << currentValue << endl;
cout << "*pointer: " << *pointer << endl;
cout << "History of integers stored in currentValue: ";
for (int i = 0; i < historyValues.size(); i++) {
cout << historyValues[i] << " ";
}
cout << endl;
cout << "Program finished" << endl;
return 0;
}
The only place in this program where pointer refers to a dynamic memory block that can be freed is between pointer = new int; and pointer = 0; If you move the delete pointer between those two lines, you'll be fine.
The result of the change is then:
pointer = new int;
delete pointer;
pointer = 0;
However, you might as well just remove all three of those lines and start with pointer = ¤tValue; because your code never uses the dynamically allocated int.
Also, your comment "increment pointer" is incorrect. You are incrementing the target of the pointer, not the pointer.
(Disclaimer: Pointers in C++ is a VERY popular topic and so I'm compelled to believe that someone before me has already raised this point. However, I wasn't able to find another reference. Please correct me and feel free to close this thread if I'm wrong.)
I've come across lots of examples that distinguish between pointer to first element of array and pointer to the array itself. Here's one program and its output:
//pointers to arrays
#include <iostream>
using namespace std;
int main() {
int arr[10] = {};
int *p_start = arr;
int (*p_whole)[10] = &arr;
cout << "p_start is " << p_start <<endl;
cout << "P_whole is " << p_whole <<endl;
cout << "Adding 1 to both . . . " <<endl;
p_start += 1;
p_whole += 1;
cout << "p_start is " << p_start <<endl;
cout << "P_whole is " << p_whole <<endl;
return 0;
}
Output:
p_start is 0x7ffc5b5c5470
P_whole is 0x7ffc5b5c5470
Adding 1 to both . . .
p_start is 0x7ffc5b5c5474
P_whole is 0x7ffc5b5c5498
So, as expected, adding 1 to both gives different results. But I'm at a loss to see a practical use for something like p_whole. Once I have the address of the entire array-block, which can be obtained using arr as well, what can I do with such a pointer?
For single arrays, I don't think there's much point to it. Where it becomes useful is with multi-dimensional arrays, which are arrays of arrays. A pointer to one of the sub-arrays is a pointer to the row, and incrementing it gets you a pointer to the next row. In contrast, a pointer to the first element of the inner array is a pointer to a single element, and incrementing it gets you the next element.
int (*)[10] is a "stronger" type than int* as it keeps size of the array,
so you may pass it to function without passing additional size parameter:
void display(const int(*a)[10]) // const int (&a)[10] seems better here
{
for (int e : *a) {
std::cout << " " << e;
}
}
versus
void display(const int* a, std::size_t size) // or const int* end/last
{
for (std::size_t i = 0; i != size; ++i) {
std::cout << " " << a[i];
}
}
So, I have been trying to learn C++ and in the tutorial book that I am reading, I have gotten stuck on a problem of pointers-to-pointers. What I am trying to do change the pointer a pointer-to-pointer is pointing to without changing the value of the original pointer. Here's some code...
#include <iostream>
void testFunc(int **func_p_to_p) {
int *createdPointer = new int(10);
*func_p_to_p = createdPointer;
cout << **func_p_to_p << endl; //prints 10 as I expect
}
int main() {
int **main_p_to_p = NULL;
int *mainPointer = new int(5);
main_p_to_p = &mainPointer;
testFunc(main_p_to_p);
cout << **test << endl;//prints 10, I expect this...
cout << *mainPointer << endl; //prints 10 as well, I don't want that.
}
I asked a similar question about this earlier, here and I understand sort of what is going on. However, I can't seem to figure out how I would change where a pointer-to-pointer is pointing to without changing the original value. Could anyone explain how I would do this? Thanks.
In the line
*func_p_to_p = createdPointer;
you first follow your pointer-pointer to what it is pointing to: The address of int *mainPointer.
Next you assign a new value to this pointer, the value of createdPointer which is the address of new int(10).
So your mainPointer is now changed to target the same memory as createdPointer. Does this make any sense to you?
You can't do that. main_p_to_p points to mainPointer, so modifying *main_p_to_p modifies mainPointer, full stop.
You might be looking for this, though:
int main() {
int **main_p_to_p = NULL;
int *mainPointer = new int(5);
int *secondPointer = mainPointer;
main_p_to_p = &secondPointer;
// prints 5 5 5
cout << *mainPointer << " " << *secondPointer << " " << **main_p_to_p << std::endl;
testFunc(main_p_to_p);
// prints 5 10 10
cout << *mainPointer << " " << *secondPointer << " " << **main_p_to_p << std::endl;
}
Note that you don't need the main_p_to_p variable, but I left it in for consistency with the question.
I'm not entirely sure why I'm getting a segfault for this piece of code. I have an array of object pointers I want to create. Here is my code.
edge **test = new edge*[a]; //Edge is a predefined class I have created. a is a my size of my array.
graphCreate2(test, vertices, roads, a); //Note roads is an edge class I have already created also
However, when I try to access edge ** test's elements, I get a segfault. Here's how I accessed it.
void graphCreate2(edge **test, int vertices, edge *roads, int a)
{
for(int i = 0; i < a; i++)
{
e[i]->setEdgeSrc(roads[i].getEdgeSrc());
e[i]->setEdgeDes(roads[i].getEdgeDes());
e[i]->setLength(roads[i].getLength());
cout << e[i]->getLength() << " " << e[i]->getEdgeSrc() << " " << endl;
}
}
Might anyone know why I'm getting this segfault? I thought I allocated memory to it as the constructor is called when creating the array Thanks!
The constructor is not called for each edge. You're only creating the array of pointers, but they point to garbage.
You need to create them all in a loop.
void graphCreate2(edge **test, int vertices, edge *roads, int a)
{
for(int i = 0; i < a; i++)
{
test[i] = new edge(); // create the edge
test[i]->setEdgeSrc(roads[i].getEdgeSrc());
test[i]->setEdgeDes(roads[i].getEdgeDes());
test[i]->setLength(roads[i].getLength());
cout << test[i]->getLength() << " " << test[i]->getEdgeSrc() << " " << endl;
}
}
I found a function to resize an array and am having trouble understanding how it works (or if it's working properly). For testing I set the "temp" array to a new value and "startCounter" does get assigned to that value, however the memory location for startCounter doesn't change. Here is my code:
int * startCounter;
void resizeArray(int *&arraySent,int origSize,int newSize) {
output << "&arraySent " << &arraySent << endl;
output << "arraySent[0] " << arraySent[0] << endl;
int* temp = new int[newSize];
output << "&temp " << &temp << endl;
for (int i=0; i<origSize; i++) {
temp[i] = arraySent[i];
}
temp[0]=744;
delete [] arraySent;
arraySent = temp;
output << "&arraySent " << &arraySent << endl;
}
//....
startCounter = new int [3];
startCounter[0]=345;
output << &startCounter << endl;
resizeArray(startCounter,3,10);
output << "startCounter[0]" << startCounter[0] << endl;
output << "&startCounter" << &startCounter << endl;
Here is the output I get from this:
&startCounter 0x60fab8
&arraySent 0x60fab8
arraySent[0] 345
&temp 0x82cfe54
&arraySent 0x60fab8
startCounter[0] 744
&startCounter 0x60fab8
My question is, why does the memory location of startCounter not change from 0x60fab8 after deleting it and assigning it to the new "temp" array? Shouldn't it now become 0x82cfe54?
P.S. I understand about vectors and such but am mainly concerned with understanding how this particular function works.
void resizeArray(int *&arraySent,int origSize,int newSize) {
output << "&arraySent " << &arraySent << endl;
outputs the address of the pointer variable, not the address that it holds.
simply omit the address operator to get the (probably) intended effect
&startCounter is the address of the pointer, not the address it points to. it's value won't change. simply use startCounter.