C++中引用传递地址的理解

Understanding Passing Address by Reference in C++

本文关键字:地址 引用 C++      更新时间:2023-10-16

我写了一段简单的C++代码,通过引用传递地址。

我将一个变量(比如y)和一个数组(比如arr)的地址传递给一个类。arry都将在类内进行修改。我希望在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;
}
  1. 在A::increment()函数中,我直接为数组赋值,而不分配内存。这样做安全吗?如果没有,我如何分配内存,以便我仍然可以在main()中获得修改后的数组值
  2. 为什么我通过&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.第一件事:我没有看到任何构造函数只接受一个参数。

  1. 阅读"未定义行为(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;