1

我听说当我们将相同的地址分配给两个不同的指针时会出现悬空指针问题。这是由于两个指针都指向相同的内存位置,并且如果使用一个指针中的地址释放内存;它仍然可以从第二个指针访问(甚至可以从第一个指针访问,如果未设置为 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 mint 15

g++ --version的输出:

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

1 回答 1

2

问题是,你是按价值传递的。
因此,您的参数有自己的地址,这些地址与您的指针不同。你想要的是通过指针或引用传递:

这里的例子:

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

正如您所看到的,给定指针/引用(ptr1 && ptr2)的所有地址都是相同的,因为值是相同的。但是参数的地址是不同的。

编辑

复制指针总是浅拷贝。表示所有char*字符串副本,但age不是浅的。对于深拷贝,每个 Player 实例都需要为每个值分配自己的内存。

由于这是 C++,您可能应该使用std::stringover 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
};

否则你必须自己处理分配和删除。这看起来像:

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

您还必须重载 operator= 因为上面的示例仅适用于构造函数...

更喜欢使用std::string

编辑2:

我忘了提到你没有复制构造函数。Player p1=p2; // this is initialization需要一个复制构造函数,否则将使用编译器生成的构造函数,最终会出现浅拷贝。

于 2013-10-21T13:30:38.707 回答