C++中引用传递地址的理解
Understanding Passing Address by Reference in C++
我写了一段简单的C++代码,通过引用传递地址。
我将一个变量(比如y)和一个数组(比如arr)的地址传递给一个类。arr和y都将在类内进行修改。我希望在main()中有修改后的值。
请在下面的代码中找到我的问题,因为这样更容易。谢谢
#include <iostream>
using namespace std;
class A
{
public:
// Assign values to the array and increment _x.
void increment()
{
(*_x)++;
(*_arr)[0] = 1; // Q1. Is it safe to directly access the array like this.
(*_arr)[1] = 2; // Don't I have to allocate memory to the array ?
(*_arr)[2] = 3;
}
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x)
{
*_arr = arr;
}
private:
int* _x;
int** _arr;
};
int main()
{
int y = 9;
int arr[5];
int *pY = &y;
int *pArr = arr;
A *obj1 = new A(pArr, pY);
// This gives a compile time error. warning: initialization of non-const reference int *&' from rvalue `int *'
// A *obj1 = new A(&y); <-- Q2. Why does this give a Compile Time Error ?
obj1->increment();
cout << "y : " << y << endl;
cout << "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << endl;
cout << endl;
return 0;
}
- 在A::increment()函数中,我直接为数组赋值,而不分配内存。这样做安全吗?如果没有,我如何分配内存,以便我仍然可以在main()中获得修改后的数组值
- 为什么我通过&y给A的构造函数
提前谢谢。
问题1
在A::increment()函数中,我直接为数组赋值,而不分配内存。这样做安全吗?如果没有,我如何分配内存,以便仍然可以在main()中获得修改后的数组值?
回答
是的,它是安全的。
问题2
为什么我通过&y给A的构造函数?
回答
&y
不是左值。因此,在参数类型为int*&
的情况下不能使用它。
发布代码中的问题
*_arr = arr;
这是一个问题,因为_arr
尚未被初始化以指向有效的存储器。在_arr
尚未初始化时使用*_arr
会导致未定义的行为。您可以将_arr
的类型更改为:
int* _arr;
并稍微简化您的代码。
class A
{
public:
// Assign values to the array and increment _x.
void increment()
{
(*_x)++;
_arr[0] = 1; // Q1. Is it safe to directly access the array like this.
_arr[1] = 2; // Don't I have to allocate memory to the array ?
_arr[2] = 3;
}
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x),
_arr(arr)
{
}
private:
int* _x;
int* _arr;
};
而不改变CCD_ 7中的任何内容。
这很少是您想要的;T**
通常是数组的数组,或者是要在调用方的作用域中修改的指针值。然而,这两者似乎都不是你在这里所做的。
当且仅当_arr
已初始化为一个非常量数组数组时,修改*_arr[0]
是安全的;当且仅在(*_arr)[0]
已初始化为指向一个非常数数组的指针时,修改它是安全的。这两种情况似乎都不是,但如果是,您可能需要显式地给出数组长度。
在本例中,&y
是一个常数。您不能修改它,因此不能将它作为非常量变量传递。您可以声明一个指针int *py = &y;
并传递它。但考虑一下这是否是你想做的
顺便说一句,使用以下划线开头的标识符不是一种好的风格,因为按照标准,它们是留给编译器使用的。
你应该告诉我们你正在尝试做什么。在我看来,在C++中毫无理由地使用原始指针/数组和裸新/(缺失?)删除是无稽之谈。我还想指出,对类成员使用_prefix并不是一种好的做法。通常前导_用于std实现。如果您坚持使用m_prefix,我建议您使用它。为什么要给_arr类型int**?应该是2D阵列吗?此外,通过引用传递指针实际上没有意义。指针已经是指针了,如果你知道我的意思,就把指针传来传去吧。
我只是假设你这样做是为了理解手动内存管理或指针算法,或者——等等,对吧:告诉我们你想做什么以及为什么。尽管如此,我不明白你的课是为了什么:
#include <iostream>
void increment(int& x, int *arr, int sz)
{
++x;
for (int i = 0; i != sz; ++i)
{
// this just numbers the values respectively (starting at 1)
arr[i] = i + 1;
}
}
int main()
{
using namespace std;
int y = 9;
const int sz = 5;
int arr[sz];
increment(y, arr, sz);
cout << "y : " << y << 'n'
<< "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << "nn";
}
要回答您的问题:2.第一件事:我没有看到任何构造函数只接受一个参数。
- 阅读"未定义行为(UB)"的起点:C++程序员应该知道的所有常见的未定义行为是什么
我再怎么重复也不为过,我不明白你要做什么,这让我很难给出可靠的建议。
我试着修正你的版本。。还是很可怕。。。我强烈建议大家阅读std::array,std::vector。也许是指针、C风格数组以及如何将C风格数组作为函数参数传递(注意:对于常规C++编程,通常不会这样做/使用)。
#include <iostream>
class A {
public:
// Assign values to the array and increment m_x.
void increment()
{
++(*m_x);
m_arr[0] = 1;
m_arr[1] = 2;
m_arr[2] = 3;
}
A (int* arr, int* x):
m_x(x), m_arr(arr)
{
}
private:
int* m_x;
int* m_arr;
};
int main()
{
using namespace std;
int y = 9;
int arr[5];
A obj1(arr, &y);
obj1.increment();
cout << "y : " << y << 'n'
<< "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << "nn";
A obj2(arr, &y);
obj2.increment();
cout << "y : " << y << 'n'
<< "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << "nn";
}
你还应该阅读非指针/引用及其差异
事实上,我正在努力让你的编程生活更轻松。抱歉回答太长。
回答您的第一个问题
在A::increment()函数中,我直接为数组,而不分配内存。这样做安全吗?如果没有,我怎么能分配内存,这样我仍然可以在中获得修改后的数组值main()?
您在main()中的行中分配了内存
int arr[5];
在类设计方面,您定义了类构造函数来接受引用参数,这意味着必须向每个参数传递一个现有的int*:
A (int* &arr, int* &x)
当你调用构造函数时,你会这样做:
A *obj1 = new A(pArr, pY);
所以在这个程序中,你所做的是安全的。如果您希望在另一个上下文中使用此类,那么潜在的危险是main()中的arr数组包含的元素少于3个,因为您的increment()函数会初始化数组的第三个元素。
回答您的第二个问题
为什么我通过&y给A的构造函数?
在您的原始构造函数中
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x)
{
*_arr = arr;
}
在初始化_arr
之前,您正在取消对它的引用。解决这个问题的一种方法是这样做:
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x)
{
_arr = new (int*);
*_arr = arr;
}
// Destructor
~A ()
{
delete _arr;
}
顺便说一句,您还可以在main()中使用new
。无论何时使用new
,都应该使用delete
以避免内存泄漏。因此,在程序的底部,在return
语句之前,添加以下内容:
delete obj1;
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 如何从绝对地址的 C 样式指针创建对C++对象的引用
- 右值引用转换后的地址更改
- 运行时错误:引用绑定到类型"int"的未对齐地址0xbebebebebebebec6,这需要 4 个字节对齐 (stl_vector.h)
- 获取通用/前向引用地址有什么意义?
- 按引用传递和按地址传递之间的差异
- C++ / Qt:如何检测主机名或IP地址何时引用当前系统?
- 常量引用函数参数的地址何时唯一?
- 通过引用传递是否涉及复制地址
- 总是引用的地址等于源地址
- 在函数中传递变量的指针和引用/地址
- 为什么取消引用的指针指向指针的 std::cout 会导致 -fsanitize=地址投诉?
- 如何通过引用获取引用变量的地址?
- 取消引用地址时是否可以重定向到其他地址?
- 在 C++ 03 中,如何引用一个被煽动的模板函数的地址
- 取消引用的输入迭代器的地址?istream_iterator的情况
- 赋值不起作用,但带有取消引用运算符的地址起作用?
- 变量循环范围会导致返回局部变量的地址引用
- 使用cout,如何将char转换为变量的地址/引用(?)
- 为什么函数不能更改其参数对象的地址/引用值?