سؤال

I have heard that dangling pointer problem arises when we assign same address to two different pointers. That is due to both pointers point to same memory location and if memory is freed using address in one pointer; it can still be accessible from the second pointer(or even from the first pointer, if not set to null, I am not discussing this case).

In the following code, I have tried different scenarios in which same memory location should be assigned to different pointers, but apparently in every scenario it is allocating new memory. Why is it so? In every case deep copies are being created.

#include<iostream>

using namespace std;

class Player
{
    public:
        char * name;
        char * countryName;
        char * gameName;
        int age;

        Player()
        {
        }

        Player(char * n, char * c, char * g,int a)
        {
            name=n;
            countryName=c;
            gameName=g;
            age=a;
        }
};


void printAddresses(Player p,Player p3)
{
    cout<<endl<<&p3<<endl<<&p<<endl;
    cout<<endl<<&p3.name<<endl<<&p.name<<endl;
    cout<<endl<<&p3.countryName<<endl<<&p.countryName<<endl;
    cout<<endl<<&p3.gameName<<endl<<&p.gameName<<endl;
    cout<<endl<<&p3.age<<endl<<&p.age<<endl;
}

int main()
{
    Player *p2=new Player;

    Player *p4=p2;

    // p2 is a pointer and p4 is also a pointer initialized from p2. But the following function prints the memory addresses, and it shows that both objects have different memory addresses. And data members also have different memory locations
    printAddresses(*p4,*p2);

    return 0;
}

I have also tried a lot of scenarios for initializing the pointers. But in each case it appears that they have separate memory addresses, and also corresponding data members also have different memory addresses.

So in which case dangling pointer problem can arise here? OR how can I make a shallow copy here? Is this c++ standard/version(written below) behaves like this or am I missing something?

OS : Linux mint 15

Output of g++ --version:

g++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3
Copyright (C) 2012 Free Software Foundation, Inc.
هل كانت مفيدة؟

المحلول

The problem is, you are passing by value.
So your parameter have their own addresses which are differnet from your pointers. What you want is passing by pointer or refernce:

see example here:

// by pointer
void printAdressesPtr(int* p1, int* p2) {
    std::cout << "p1 - ptr: " << p1 << " - value: " << *p1 << std::endl;
    std::cout << "p2 - ptr: " << p2 << " - value: " << *p2 << std::endl;

    std::cout << "p1 - ptr ref: " << &p1 << std::endl;
    std::cout << "p2 - ptr ref: " << &p2 << std::endl;
}

// by reference
void printAdressesRef(int& r1, int& r2) {
    std::cout << "r1 - ref: " << &r1 << " - value: " << r1 << std::endl;
    std::cout << "r2 - ref: " << &r2 << " - value: " << r2 << std::endl;
}

// by value (copy)
void printAdressesVal(int v1, int v2) {
    std::cout << "v1 - ref: " << &v1 << " - value: " << v1 << std::endl;
    std::cout << "v2 - ref: " << &v2 << " - value: " << v2 << std::endl;
}

int main() {
    int* ptr1 = new int(123);
    int* ptr2 = ptr1;

    printAdressesPtr(ptr1, ptr2);
    printAdressesRef(*ptr1, *ptr2);  
    printAdressesVal(*ptr1, *ptr2);

    return 0;
}

As you can see all addresses of the given pointers/referecces (ptr1 && ptr2) are the same, as the values are. But the addresses for the parameters are different.

Edit

Copying pointers is always shallow copy. Means all char* string copies, but age isn't shallow. For a deep copy every instance of Player needs his own memory allocated for every value.

Since this is C++ you probably should use std::string over char*:

class Player {
public:
  std::string name;
  std::string countryName;
  std::string gameName;
  int         age;

  Player() {}

  Player(std::string const& n, std::string const& c, std::string const& g, int a)
    : name(n), countryName(c), gameName(g), age(a) {} // this are deep copies

  // copy constructor
  Player(Player const& cpy)
    : name(cpy.name)
    , countryName(cpy.countryName)
    , gameName(cpy.gameName)
    , age(cpy.age) {} // this are deep copies
};

Otherwise you have to look after allocating and deleting by yourself. this would look like:

class Player {
public:
  char* name;
  char* countryName;

  Player()
    : name(nullptr), countryName(nullptr) {}

  Player(char* n, char* c) {
    // deep copy. name has his own memmory allocated and the value is copied 
    // from n to name
    name = new char[strlen(n) + 1]; 
    strcpy(name, n);

    // shallow copy. contryName and c have the same address of the value.
    // changing contryName of P2 is also changing contryName of P1. also there is no
    // guarantee that enough space is allocated.
    contryName = c;
  }


  // copy constructor
  Player(Player const& cpy) {
    // this is a deep copy. name has his own memmory allocated and the value is copied
    // from n to name
    name = new char[strlen(cpy.name) + 1]; 
    strcpy(name, cpy.name);

    // shallow copy. contryName and c have the same address of the value.
    // changing contryName of P2 is also changing contryName of P1. Also there is no
    // guarantee that enough space is allocated...
    contryName = c;
  }

  ~Player() {
    if(name != nullptr)
      delete name;
    name = 0;

    // this will also delete contryName of P1. access from P1 is undefined behavior...
    if(contryName != nullptr)
      delete[] contryName;
    contryName = 0;
  }
};

Also you have to overload operator= since the example above is only for constructor...

Prefer using std::string.

Edit2:

I forgot to mention that you don't have a copy constructor. Player p1=p2; // this is initialization need a copy constructor otherwise the compiler generated one will be used which will end up in shallow copies.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top