【发布时间】: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
可以看出,当构造函数被调用时,pa 和 pb 都是有效的内存地址,用于保存值 15 和 16 的整数。但是,一旦构造函数完成执行,如果我尝试访问p.pa 的值,它返回 0x3,而不是之前的内存地址。当然,这本身就是一个问题,也会导致复制构造函数出现问题。
我找到了两种解决方法。
-
首先是通过移除
pa和pb的类型来改变构造函数的定义。那就是将int* pa = new int(a);更改为pa = new int(b)。对pb重复相同的操作。现在,p.pa 返回正确的内存地址。 -
第二种是注释掉
hp的初始化和删除。也就是说,从main()函数中删除这些行:
numPair *hp = new numPair(23, 42);
delete hp;
我真的不明白为什么指定指针的类型会导致这些错误,或者事实上,为什么 p.pa 和 p.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.