Get The Object Pointer Is Pointing To - c++

I have a QList which I have inserted pointers of objects into. I am trying to iterate through this QList to read the name of these objects. Whenever I do so, I am getting the address of these objects as oppose to reading the object name itself. I am wondering how would I be able to read the object name instead of the address?
QList<MyObject*> newObjectList;
QList<MyObject*>::iterator i;
MyObject *pNewObject = new MyObject(name);
MyObject.append(pNewObject);
for (i = newObjectList.begin(); i != newObjectList.end(); i++) {
cout << "\n" << *i << "\n";
}

When you're dereferencing i, you need to call the function to get the name from your object. Something like this:
for (i = newObjectList.begin(); i != newObjectList.end(); i++) {
// i right now is the iterator, and points to a pointer. So this will need to be
// dereferenced twice.
cout << "\n" << (*i)->getName() << "\n";
}

When you derenference the iterator i (i.e. *i) you a a reference to an object of type MyObject* which is a pointer, you have to dereference that again to get a reference to your object:
*(*i)

Related

Can't I change the pointer to another one when I use new operator in C++?

I ask you questions because there is something I don't understand while studying dynamic allocation in C++.
Can I delete "St" and use "ptr" instead if I move the address stored in St to another pointer "ptr" when the dynamically allocated memory is pointed by the St pointer?
If I delete the "St" dynamic allocation, can I move the address to another pointer and delete the "St" immediately because the allocated space does not disappear but disconnects the pointer "St" from the space?
Below is the code I was writing.
Student is a structure.
int main()
{
case 1:
{
Student* ptr = NULL;
Student* St = new Student[10];
ptr = St;
delete[] St;
St = NULL;
break;
}
case 2:`enter code here`
{
printdata(ptr);break;
}
}
Once you've called delete[] on the pointer you get back from new Student[10], the value of that pointer is indeterminate. Both St and ptr are exactly that, but you reassign St. (Since C++11, use nullptr rather than NULL.)
The behaviour of dereferencing the pointer you get back from new Student[10] following the delete[] is undefined.
You can’t use memory you just freed. Memory at that address might still be usable (event till program closes), but there is no guarantee and program might use it for something else.
Can I delete "St" and use "ptr" instead if I move the address stored
in St to another pointer "ptr" when the dynamically allocated memory
is pointed by the St pointer?
If St points toward your array, you can make ptr point toward it as well, but it is not a transfer. What you actually transfer is the adress of the object you are pointing to. The 2 pointers will point toward the same object.
If you delete the object with delete[] (you delete the object, not the pointer), then the 2 pointers will point toward nothing. So what you actually want to do here is make ptr point toward the same object, and then make St point toward null.
Student* ptr = NULL;
Student* St = new Student[10];
ptr = St;
St = NULL;
Edit : If it may help you understand, here is what you can display ...
int x = 4;
int* p = &x;
cout << "x = " << x << " value of x." << endl;
cout << "&x = " << &x << " adress of x." << endl;
cout << "*p = " << *p << " the value of what p points to." << endl;
cout << "p = " << p << " the actual value of p which is the adress of x." << endl;

Adding pointers to objects to a vector

I am trying to add pointers to an object to a vector in a function like this:
vector:
vector<struct Node*> vars;
function:
void fill_vec(){
struct Node* temp;
temp = new Node();
cout << token << endl;
temp->name = token;
temp->value = 0;
cout << temp << endl;
vars.push_back(temp);
}
fill_vec is being called in a while loop that stops when there aren't anymore variable names.
It is adding the correct amount of nodes to the vector, but everything is pointing to the same object. Token is being parsed.
output of above:
a
0x9c6010
b
0x9c6050
printing vector:
void print_vars(){
for(int i = 0; i < vars.size(); i++){
cout << "Name:" << vars[i]->name << endl;
cout << "Value:" << vars[i]->value << endl;
}
}
output:
Name:b
Value:0
Name:b
Value:0
My thought was that when I allocated new memory, the address would change. When I print the address of temp each time I call the function, the address is the same. I was printing the address wrong. The address is different for each call of the function. Thank you in advance for the help.
My thought was that when I allocated new memory, the address would change.
It does indeed.
When I print the address of temp each time I call the function, the address is the same.
That is because you are printing out the address of a local variable, which happens to reside at the same stack memory address each time fill_vec() is called. You should be printing out the memory address of the allocated Node instead.
Change this line:
cout << &temp << endl;
To this:
cout << temp << endl;
As it turns out, it was the token. Token is a char* and I was not using strdup() on it. So every time I updated token, name was being changed in each object.

Why can't a function change its argument object's address/reference value?

I learned that in Java and C, you can assign a pointer, pass the pointer to a method, follow the pointer in the method and change the data that was pointed to. However, you cannot change where that pointer points.
I thought I could see a different behavior in C++ due to its pass-by-reference feature, but my code seems to agree with the above statement...
void reassign(string & a);
int main()
{
string x = "abcd";
cout <<"x is " << x <<" at " << &x <<endl; //"x is abcd at 0x7bc7ebd5b720"
reassign(x);
cout <<"x is " << x <<" at " << &x <<endl; //"x is efgh at 0x7bc7ebd5b720"
}
void reassign(string & a)
{
a = string("efgh");
}
Since "string()" constructs a new string, why doesn't the "reassign" function change the original string's address?
Once an object is allocated, nothing can change its address. You can change its content (that is what your program does) but the address will stay the same for the lifetime of the object.
If you create an object dynamically with new, you would be able to assign a different object to the same pointer. However, the rule would stay the same: the address of the old object would not change, but you would be able to assign a new object to an old pointer.
void reassign(string* & a);
int main() {
string *x = new string("abcd");
cout <<"x is " << *x <<" at " << x <<endl; //"x is abcd at 0x95b7008"
reassign(x);
cout <<"x is " << *x <<" at " << x <<endl; //"x is efgh at 0x95b7030"
delete x;
return 0;
}
void reassign(string* & a) {
string *old = a;
a = new string("efgh");
delete old;
}
Demo.
You are confused because your analogy is not right. In Java, there is no such thing as an "argument object", because "objects" themselves are not values in Java (there are no "object types" in Java). The only types in Java are primitive types and reference types, where "references" are pointers to objects. So in Java you can only have pointers to objects as the value of a variable or parameter, and you only deal with objects through pointers to objects.
"you cannot change where that pointer points" is a consequence of pass-by-value. Java is always pass-by-value, which means assignment to the parameter cannot change the value of a passed variable. Remember that variables can only be of primitive type or reference type. Here you are talking about reference type. So the "value" of a variable of reference type is the reference (pointer to object), i.e. the address of the object it points to. Hence, you cannot change the value means you cannot change where the pointer points.
For example, in Java you might have something like this:
public static void reassign(String a) {
a = new String("efgh");
}
public static void main(String[] args) {
String x = "abcd";
System.out.printf("x is %s at %x\n", x, System.identityHashCode(x)); // x is abcd at 25154f
reassign(x);
System.out.printf("x is %s at %x\n", x, System.identityHashCode(x)); // x is abcd at 25154f
}
Here, x in main is a pointer to an object. a in reassign is also a pointer to an object. Assigning to the pointer parameter a in reassign has no effect on the passed pointer variable x (i.e. it does not affect where the pointer points to) because it's pass-by-value.
The equivalent of the above code in C++ would be like this:
void reassign(string *a) {
a = new string("efgh");
}
int main() {
string *x = new string("abcd");
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x82b1008
reassign(x);
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x82b1008
return 0;
}
In addition to the pass-by-value shown above, C++ also has pass-by-reference, where assignment to a parameter has the same effect as assigning to the passed variable in the calling scope. Here is the exact same thing as above but with pass-by-reference:
void reassign(string *&a) {
a = new string("efgh");
}
int main() {
string *x = new string("abcd");
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x8673008
reassign(x);
cout << "x is " << *x <<" at " << x << endl; // x is efgh at 0x8673030
return 0;
}
Note that in none of the cases here did we change the object pointed to. We simply created a new object and tried to change the pointer to point to this object. The old object is still unchanged. The ability to change an object is an independent and orthogonal issue from pass-by-value and pass-by-reference, so we do not go into it here.

Accessing Vector of Pointers?

I'm trying to get a simple bit of code to work. I have a function called 'get_object_radius' which searches an area for instances of 'Creature', and pushes their pointers to a vector, then returns the vector.
I then want to cycle through them all and display their names from outside the function. I'm pretty sure I'm adding them to the vector correctly, but I'm not cycling through the vector of pointers correctly, am I?
Here's the relevant code snippet (that doesn't work):
//'get_object_radius' returns a vector of all 'Creatures' within a radius
vector<Creature*> region = get_object_radius(xpos,ypos,radius);
//I want to go through the retrieved vector and displays all the 'Creature' names
for (vector<Creature*>::iterator i = region.begin(); i != region.end(); ++i) {
cout<< region[i]->name << endl;
}
Any ideas what I'm doing wrong?
http://www.cplusplus.com/reference/stl/vector/begin/
You dereference the iterator to get to the underlying object.
cout << (*i)->name << endl;
Try:
//I want to go through the retrieved vector and displays all the 'Creature' names
for (vector<Creature*>::iterator i = region.begin(); i != region.end(); ++i) {
cout << (*i)->name << endl;
}
You need to dereference the iterator (using the * operator), which then gives you Creature* pointer.
To get the element iterator is pointing at, you dereference it (like a pointer, but iterators are not necessarily pointers). So your code should look like this:
// auto is C++11 feature
for (auto it = region.begin(); it != region.end(); ++it) {
Creature *p = *it;
std::cout << p->name << "\n";
}
In C++11 you also get range for, which hides iterators from your view:
for (Creature *p : region) {
std::cout << p->name << "\n";
}

double pointer reference in C++

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