【问题标题】:Why is defining the type of a pointer causing issues in my code?为什么定义指针的类型会导致我的代码出现问题?
【发布时间】:2020-11-29 11:50:00
【问题描述】:

在初始化一个指针在堆中分配内存时,我们应该指定类型为指针吗?也就是说,应该是:

int* ptr = new num;

ptr = new num;

两者似乎都有效,我的印象是第一种方法更好,但这样做会导致下面的代码出现一些问题。

我有一个包含两个成员变量的类,这两个变量都应该是指向堆上新 int 的指针。当复制构造函数被调用时,它应该在堆中分配新的内存,但是复制传入参数的指针所指向的整数值。


#include <iostream>
using namespace std;

// Header file
#pragma once

class numPair {
  public:
    int *pa,*pb;
    numPair(int, int);
    numPair(const numPair &);
 };

// Implementation file
#include "Cube.h"
#include <iostream>
using namespace std;

numPair::numPair(int a, int b) {
   cout << "Constructor invoked!" << endl;

   int* pa = new int(a);
   cout << "pa = " << pa << endl;
   cout << "*pa = " << *pa << endl;

   int* pb = new int(b);
   cout << "pb = " << pb << endl;
   cout << "*pb = " << *pb << endl;

}

numPair::numPair(const numPair& other) {
   cout << "Copy invoked!" << endl;
  int* ptr = other.pa;
  cout << "ptr in copy: " << ptr << endl;
}
 
// main.cpp file
#include "Cube.h"
#include <iostream>
using namespace std;

int main() {
  numPair p(15,16);
  cout << "p.pa = " << p.pa << endl;
  numPair q(p);
  numPair *hp = new numPair(23, 42);
  delete hp;
  return 0;
}

main.cpp文件的输出为:

Constructor invoked!
pa = 0x5594991a7280
*pa = 15
pb = 0x5594991a72a0
*pb = 16
p.pa = 0x3
Copy invoked!
ptr in copy: 0x3
Constructor invoked!
pa = 0x5594991a72e0
*pa = 23
pb = 0x5594991a7300
*pb = 42

可以看出,当构造函数被调用时,papb 都是有效的内存地址,用于保存值 15 和 16 的整数。但是,一旦构造函数完成执行,如果我尝试访问p.pa 的值,它返回 0x3,而不是之前的内存地址。当然,这本身就是一个问题,也会导致复制构造函数出现问题。

我找到了两种解决方法。

  1. 首先是通过移除papb的类型来改变构造函数的定义。那就是将int* pa = new int(a); 更改为pa = new int(b)。对pb 重复相同的操作。现在,p.pa 返回正确的内存地址。

  2. 第二种是注释掉hp的初始化和删除。也就是说,从main() 函数中删除这些行:

numPair *hp = new numPair(23, 42);
delete hp;

我真的不明白为什么指定指针的类型会导致这些错误,或者事实上,为什么 p.pap.pb 的内存地址会因为 another 类的实例,尤其是考虑到 hp 是在 p 之后初始化的事实。

【问题讨论】:

  • int* pa = new int(a); 这会隐藏同名的pa 成员变量。
  • @anonymous1a 该行分配了一个new int,并将指向它的指针保存在构造函数中定义的局部变量pa 中,然后在构造函数的末尾超出范围。成员变量pa 保持不变。参见例如Priority between local variable and class attribute in case of name conflict
  • @anonymous1a 我在之前的评论中添加了一个链接,其中包含更多详细信息。就名称解析而言,本地 pa 的类型无关紧要。您可以改为定义 double pa = 3.14;,在这种情况下,pa 也将引用构造函数内的本地(双)变量。
  • @anonymous1a 这里的关键点是这两个定义出现在不同的范围内。这确实应该在您使用的教科书中进行解释。
  • 你需要一本合适的 C++ 书籍。 Here's a starting point.

标签: c++ pointers


【解决方案1】:

简短的回答是您误解了局部作用域变量和类成员之间的区别。考虑这一点的一种方法是,您只需要告诉您的程序标识符的类型一次

在您的类定义中,您使用类型 int (int *pa,*pb) 声明了两个指针,但在您的构造函数 numPair::numPair(int a, int b) 中,您创建了两个 new 指针声明( int* paint* pb) 存在于构造函数中。在类构造函数中,您可以按名称引用其成员,而无需每次都声明类型,因为您已经在类定义中声明了它们。这就是您的解决方案 #1 适合您的原因。

此外,在您的原始代码中,您正在泄漏在堆上为值分配的内存,因为您没有对这些指针调用 delete。

【讨论】:

  • 谢谢!这很有帮助!至于泄漏内存,该类还有一个自定义析构函数,它调用 delete o 指针,但这与问题无关,所以我没有在这里包含它。
猜你喜欢
  • 2012-03-16
  • 2015-10-16
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 2021-05-28
  • 1970-01-01
  • 2016-06-27
  • 1970-01-01
相关资源
最近更新 更多