【问题标题】:How to properly return a class member array as a return parameter如何正确返回类成员数组作为返回参数
【发布时间】:2014-07-23 23:36:04
【问题描述】:

我对如何使用返回参数从一个类中获取多个浮点数组感到困惑。这是一个简化的示例。

class Points
{
    private:
        float *x;
        float *y;
        float *z;
    public:
        void getCoordinates (float *retx, float *rety, float *retz);
}

void Points:: getCoordinates (float *retx, float *rety, float *retz)
{
    retx=x;
    rety=y;
    retz=z;
}

当我在函数内部进行赋值时,指针值匹配。但是,一旦我离开该函数,这些值就会发生变化。指针的范围是否受到某种限制?

基于How to properly return an array (class member) in C++?,我认为不应该是这样。讨论表明不仅可以传递指针,而且通过指针对内存的更改将影响类的原始实例。正是我期望指针工作的方式。

我尝试过的一种解决方法是使用 memcpy

void Points::getCoordinates (float *retx, float *rety, float *retz)
 {
memcpy(retx, x, sizeof(float)*numPoints);
memcpy(rety, y, sizeof(float)*numPoints);
memcpy(retz, z, sizeof(float)*numPoints);   
}

这也是我想要的方式。这种方法的缺点是我需要在调用函数中分配正确的内存量,而且我使用的内存比我认为需要的要多。

【问题讨论】:

  • 您需要将输入参数作为双指针或指针引用传递(即,您需要通过引用传递它们)。
  • 一个类 Points 存储 x、y 和 z 值的多个数组,听起来像 a bad idea。为什么不改用std::vector<Point>Point 有一个 x、y 和 z 值?
  • @FredOverflow 我实际上并没有编写“积分”类。这似乎是最简单的例子。 :)
  • 在函数返回后,您是否希望 retx/y/z 指向与 x/y/z 完全相同的数组,或者如果您想制作 副本他们?
  • 关于如何命名这个问题的任何建议,以便未来的寻求者能够更好地找到它?我觉得现在的标题可能太笼统了。

标签: c++ arrays pointers


【解决方案1】:

但是,一旦我离开该函数,值就会发生变化。指针的范围是否受到某种限制?

这是应该的。

考虑这段代码:

int f(int a) { a = 20; }

int x = 10;
f(x);

当您调用f 时,会在堆栈上创建一个位置,其中放置x (10) 中的值。然后,这个地方被命名为a,函数被执行为 a,具有 x 的值。如果修改 a(如上面的代码),x 不会被修改,因为 x 是一个不同的变量。

现在,考虑当a 是指针时会发生什么:

int g(int *a) { a = nullptr; }
int *b = new int{10};
g(b);

这里,在堆栈上为a 创建的值是一个内存地址。如果你修改地址本身(如果你修改a = nullptr;),类似上面的情况,b不受影响,只有a(即修改只在函数体内生效)。

你可以修改a所指向的地址处的值。虽然ba 是不同的变量,但是当您调用g(b) 时,两个变量(虽然不同)将包含相同的内存地址。因此,如果您更改a 指向的地址处的值,您实际上是在向客户端代码返回一个值(您并没有真正返回它,但客户端代码可以通过取消引用来访问它b)。

代码:

int g(int *a) { *a = 20; } // assign value to memory pointed to, by a
int *b = new int{10};
g(b); // a and b will point to the same value
assert(*b == 20); // evaluates to true

这是使用输出参数的C 风格。在 C 中,输出参数是一个保存地址的参数,因此修改该地址的值允许客户端代码访问该地址(就像我上面的示例中一样)。

在你的具体情况下,你的代码可以这样写(但可能不应该——见下文):

void Points::getCoordinates (float **retx, float **rety, float **retz)
{
    *retx=x;
    *rety=y;
    *retz=z;
}

每个参数都有一个额外的间接级别(即,如果您希望输出参数将地址保存为浮点数,则必须将指向该地址的指针作为参数 - 即双指针或指向一个指向浮点数的指针)。

为什么不应该

C++ 引入了引用,它允许将地址视为对象本身。 因此,对于 C++,您的代码可能如下所示:

void Points::getCoordinates (float *&retx, float *&rety, float *&retz)
{
    retx=x;
    rety=y;
    retz=z;
}

更好的是,在 C++ 中,您的代码可能应该如下所示(不确定这对于您的代码/代码库是否可行):

struct Point3d { float x, y, z; }
Point3d Points::getCoordinates() const { return Point3d{ x, y, z }; }

【讨论】:

    【解决方案2】:

    你需要使用指针引用。

        void Points:: getCoordinates (float *&retx, float *&rety, float *&retz)
    

    【讨论】:

    • 我唯一要补充的是,根据 OP 的需要,最好传递 const float*& 以防止调用者稍后使用 out 参数(显然,如果这种行为是想要的,则不要使用const)。
    猜你喜欢
    • 1970-01-01
    • 2022-01-10
    • 2015-03-20
    • 1970-01-01
    • 1970-01-01
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多