управление памятью — висячий указатель C ++ / глубокая копия / путаница в мелкой копии

Я слышал, что проблема с висящими указателями возникает, когда мы назначаем один и тот же адрес двум различным указателям. Это связано с тем, что оба указателя указывают на одну и ту же ячейку памяти и если память освобождается с использованием адреса в одном указателе; он все еще может быть доступен из второго указателя (или даже из первого указателя, если он не установлен в ноль, я не обсуждаю этот случай).

В следующем коде я пробовал разные сценарии, в которых одно и то же место в памяти должно быть назначено разным указателям, но, очевидно, в каждом сценарии оно выделяет новую память. Почему это так? В каждом случае создаются глубокие копии.

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

Я также пробовал много сценариев для инициализации указателей. Но в каждом случае оказывается, что они имеют отдельные адреса памяти, а также соответствующие члены данных также имеют разные адреса памяти.

Так в каком случае здесь может возникнуть проблема с висящим указателем? ИЛИ как я могу сделать мелкую копию здесь? Это стандарт / версия c ++ (написано ниже) ведет себя так или я что-то упустил?

ОС: Linux Mint 15

Выход из g ++ — версия:

g++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3
Copyright (C) 2012 Free Software Foundation, Inc.

1

Решение

Ваша проблема в том, что вы передаете по значению.

так что у вашего параметра есть собственные адреса, которые отличаются от ваших указателей. что вы хотите передать указателем или ссылкой:

смотри пример Вот:

// 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;

// while now the addresses of p1 and p2 are different
std::cout << "p1 - ptr adr: " << &p1 << std::endl;
std::cout << "p2 - ptr adr: " << &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. this will not work, since values are copied.
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;
}

так как вы можете видеть все адреса к указателям / ссылкам (ptr1 && ptr2) одинаковы, также все значения одинаковы, но адреса для параметров разные.

редактировать

это все мелкие копии (кроме возраста). поскольку вы просто копируете только указатели (адреса, на которые указывают указатели), а не значение членов. для глубокой копии каждому экземпляру Player нужна собственная память, выделенная для каждого значения.

Вы пометили этот вопрос как c ++, так что используйте вместо него материал c ++.

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

Player() {}

// this is not a copy constructor
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

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

в противном случае вы должны заботиться о выделении и удалении самостоятельно. это будет выглядеть так:

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

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

// this is not a copy constructor
Player(char* n, char* c) {
// this is a 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);

// this is a 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!!!! use std::string!!!
contryName = c;
}// this is a 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);

// this is a 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!!!! use std::string!!!
contryName = c;
}

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

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

также вы должны перегрузить operator =, поскольку приведенный выше пример предназначен только для конструктора …

edit2:

я забыл упомянуть, что у вас нет конструктора копирования. Player p1=p2; // this is initialization нужен конструктор копирования, в противном случае будет сгенерирован компилятор, который получится в неглубоких копиях, за исключением того, что вы используете std :: string 🙂

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]