簡體   English   中英

C ++懸空指針/深層復制/淺層復制混亂

[英]C++ dangling pointer/deep copy/shallow copy confusion

我聽說當我們將相同的地址分配給兩個不同的指針時,就會出現懸空指針問題。 這是由於兩個指針都指向相同的內存位置,並且如果使用一個指針中的地址釋放了內存; 它仍然可以從第二個指針訪問(甚至從第一個指針訪問,如果未設置為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.

您的問題是,您正在傳遞價值。

因此您的參數有自己的地址,該地址與指針的地址不同。 您想要通過指針或引用傳遞:

在這里查看示例:

// 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 && 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 Player p1=p2; // this is initialization需要一個副本構造函數,否則將使用編譯器生成的副本構造函數,除非使用std :: string :),否則它將以淺表副本結尾

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM