C ++悬空指针/深拷贝/浅拷贝混淆

时间:2013-10-21 13:10:17

标签: c++ memory-management g++ shallow-copy dangling-pointer

我听说当我们为两个不同的指针分配相同的地址时会出现悬空指针问题。这是因为两个指针指向相同的内存位置,并且如果使用一个指针中的地址释放内存;它仍然可以从第二个指针访问(甚至可以从第一个指针访问,如果没有设置为null,我不讨论这种情况)。

在下面的代码中,我尝试了不同的场景,其中相同的内存位置应该分配给不同的指针,但显然在每个场景中它都在分配新的内存。为什么会这样?在每种情况下都会创建深层副本。

#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薄荷15

输出 g ++ --version

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

1 个答案:

答案 0 :(得分:2)

你的问题是,你正在经历价值。

所以你的参数有自己的地址,这些地址与你的指针不同。你想要的是通过指针或引用传递:

参见示例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;

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

你可以看到给定指针/ refenreces(ptr1&amp;&amp; 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 =,因为上面的例子仅用于构造函数...

很快说,使用std::string

EDIT2:

我忘了提到你没有复制构造函数。 Player p1=p2; // this is initialization需要一个复制构造函数,否则将使用编译器生成的一个,除了使用std :: string之外,它将以浅拷贝结束:)

相关问题