在 C++ 中通过引用传递类成员函数返回值

发布于 2024-11-08 12:02:40 字数 1989 浏览 0 评论 0原文

我一直在寻找解决这个问题的方法,但似乎找不到。我确信这个一般性问题之前已经在某个地方被问过,但希望你能帮助解决我的具体情况...

我有一个类模板 someClass ,其中包含以下(私有)成员:

int     size_x;
int     size_y;
int     size_total;
T *     grid;

someClass 包含一个如下所示的构造函数:

someClass (const int x, const int y)
: size_x (x), size_y (y), size_total (x*y)
{
    grid = new T [size_total];
}

一个如下所示的复制构造函数:

someClass (const someClass & rhs)
{
    size_x = rhs.size_x;
    size_y = rhs.size_y;
    size_total = rhs.size_total;
    grid = new T [size_total];
    memcpy(grid, rhs.grid, size_total*sizeof(T));
}

一个如下所示的成员函数:

T * retGrid (void) const
{
    return grid;
}

以及一个如下所示的赋值运算符:

someClass & operator= (const someClass & rhs)
{
    if (this != &rhs)
    {
        size_x = rhs.size_x;
        size_y = rhs.size_y;
        size_total = rhs.size_total;
        grid = new T [size_total];
        memcpy(grid, rhs.grid, size_total*sizeof(T));
    }

    return *this;
}

我正在尝试传递以下两个 someClass对象

someClass<double> *I1 = new someClass<double>(10,10);

someClass<double> I2 = *I1;

someClass之外的函数具有以下原型的类:

int someFunction(double *arr);

此调用工作正常:

int status;
status = someFunction(I1->retGrid()); // Properly working function call

但这不行

status = someFunction(&I2.retGrid()); // Compiler gives error that says "error: invalid lvalue in unary &"

如果我像这样调用 someFunction

status = someFunction(I2.retGrid()); // Compiler gives no error but function returns error value in status

代码编译但我收到运行时错误(来自另一个函数调用的错误状态值)在 someFunction 内)。

如何正确地将 I2 传递给 someFunction

非常感谢...

I've been searching for a solution to this problem but can't seem to find one. I'm sure this general question has been asked before somewhere but hopefully you can help with my specific situation...

I have a class template someClass that contain the following (private) members:

int     size_x;
int     size_y;
int     size_total;
T *     grid;

someClass contains a constructor that looks like this:

someClass (const int x, const int y)
: size_x (x), size_y (y), size_total (x*y)
{
    grid = new T [size_total];
}

a copy constructor that looks like this:

someClass (const someClass & rhs)
{
    size_x = rhs.size_x;
    size_y = rhs.size_y;
    size_total = rhs.size_total;
    grid = new T [size_total];
    memcpy(grid, rhs.grid, size_total*sizeof(T));
}

a member function that looks like this:

T * retGrid (void) const
{
    return grid;
}

and an assignment operator that looks like this:

someClass & operator= (const someClass & rhs)
{
    if (this != &rhs)
    {
        size_x = rhs.size_x;
        size_y = rhs.size_y;
        size_total = rhs.size_total;
        grid = new T [size_total];
        memcpy(grid, rhs.grid, size_total*sizeof(T));
    }

    return *this;
}

I'm trying to pass the following two someClass objects

someClass<double> *I1 = new someClass<double>(10,10);

someClass<double> I2 = *I1;

to a function outside of the someClass class with the following prototype:

int someFunction(double *arr);

This call works fine:

int status;
status = someFunction(I1->retGrid()); // Properly working function call

but this does not

status = someFunction(&I2.retGrid()); // Compiler gives error that says "error: invalid lvalue in unary &"

And if I call someFunction like this:

status = someFunction(I2.retGrid()); // Compiler gives no error but function returns error value in status

the code compiles but I get a run-time error (a bad status value from another function call within someFunction).

How can I properly pass I2 to someFunction?

Many thanks...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

打小就很酷 2024-11-15 12:02:40

您正在尝试获取 retGrid 返回的临时对象的地址(在本例中是一个指针,但这并不重要)。因此您不能使用 & 方法。

如果没有&符号,您会将内部数组从I2传递到someFunction。如果这对您来说不好(即因为您收到某种运行时错误),请考虑复制该数组并将其传递给 someFunction

You are trying to take address of the temporary object (in this case, a pointer but this doesn't really matter) returned by retGrid. Hence you cannot use the & approach.

Without the ampersand, you would pass the internal array from I2 to someFunction. If that's not fine for you (i.e. since you get some kind of runtime error), consider making a copy of this array and passing it to someFunction instead.

陌伤ぢ 2024-11-15 12:02:40

当类中有指针并且必须为每个对象分配内存时,您需要定义复制构造函数和赋值运算符。您只添加了后者。该初始化

someClass<double> I2 = *I1;

实际上是使用复制构造函数执行的,而不是使用赋值运算符。它与 相同

someClass<double> I2(*I1);

但是,这是错误的,因为您只为网格分配内存。但是如果网格已经被分配(从之前的分配中),你就会泄漏内存。所以它应该看起来像这样:

someClass & operator= (const someClass & rhs)
{
    if (this != &rhs)
    {
        size_x = rhs.size_x;
        size_y = rhs.size_y;
        size_total = rhs.size_total;
        delete [] grid;
        grid = new T [size_total];
        memcpy(grid, rhs.grid, size_total*sizeof(T));
    }

    return *this;
}

When you have pointers in your class and you have to allocate memory for each object, you need to define a copy constructor and an assignment operator. You only added the later. This initialization

someClass<double> I2 = *I1;

is actually performed with a copy constructor, not with the assignment operator. It is identical to

someClass<double> I2(*I1);

However, it is wrong, because you only allocate memory for grid. But if grid was already allocated (from a previous assignment) you'd leak memory. So it should look like this:

someClass & operator= (const someClass & rhs)
{
    if (this != &rhs)
    {
        size_x = rhs.size_x;
        size_y = rhs.size_y;
        size_total = rhs.size_total;
        delete [] grid;
        grid = new T [size_total];
        memcpy(grid, rhs.grid, size_total*sizeof(T));
    }

    return *this;
}
微凉 2024-11-15 12:02:40

第一个问题:为什么不使用 std::vector ,而不是
尝试自己管理内存。你不显示
析构函数;我想你释放了那里的内存。但有
仍然存在问题:

  • 在复制构造函数中,您使用memcpy。这不是问题
    当您实例化 double 时,但这可能是一个问题
    对于其他类型。您应该使用 std::copy

  • 如果您使用的是 std::vector,并且仍需要 retGrid
    返回一个 T*,它将是 return &grid[0];

  • 赋值运算符已损坏。它泄露了任何以前的
    内存,如果new失败,它会将对象留在
    不一致的状态。 (必须检查自分配是
    通常是出现问题的提示。)正确的分配
    操作员将在更改之前执行所有可能失败的操作
    对象中的任何东西。您可能会搜索有关的信息
    交换习惯用法,但类似下面的内容也可以
    工作:

SomeClass&
SomeClass<T>::operator=( SomeClass const& other )
{
    T* newGrid = new T[other.size_total];
    std::copy( other.grid, other.grid + other.size_total, newGrid );
    delete [] grid;
    size_x = other.size_x;
    size_y = other.size_y;
    size_total = other.size_total;
    grid = newGrid;
    return *this;
}

如果 size_total 相等,您可能需要对此进行优化
(或size_total <= other.size_total)。

当然,如果您使用 std::vector ,编译器会生成
赋值运算符和复制构造函数就足够了;你
不必写任何东西。

  • 您对I1使用指针有什么原因吗? (或者是
    这只是一个更大背景下的产物,你可以从中
    提取了代码?)

  • 关于someFunction( &I2.retGrid() );,
    someClass::retGrid() 返回一个指针。无论是否
    您通过指针或对象调用该函数。服用
    地址结果为 T**

  • 关于最后一次调用,没有什么会导致
    您向我们展示的代码中存在问题。只要 I2
    在范围内并且没有删除它的对象,不应该有
    问题。这是调用函数的正确方法
    目的。您的代码中的问题在其他地方。

First question: why aren't use using std::vector, instead of
trying to manage the memory yourself. You don't show the
destructor; I presume you free the memory there. But there are
still problems:

  • In the copy constructor, you use memcpy. That's not a problem
    when you instantiate over double, but it could be a problem
    for other types. You should be using std::copy.

  • If you were using std::vector, and retGrid still needed to
    return a T*, it would be return &grid[0];.

  • The assignment operator is broken. It leaks any previous
    memory, and if the new fails, it leaves the object in an
    inconsistent state. (Having to check for self-assignment is
    usually a hint that something is wrong.) A correct assignment
    operator will do all operations which might fail before changing
    anything in the object. You might search for information about
    the swap idiom, but something like the following would also
    work:

.

SomeClass&
SomeClass<T>::operator=( SomeClass const& other )
{
    T* newGrid = new T[other.size_total];
    std::copy( other.grid, other.grid + other.size_total, newGrid );
    delete [] grid;
    size_x = other.size_x;
    size_y = other.size_y;
    size_total = other.size_total;
    grid = newGrid;
    return *this;
}

You might want to optimize this if the size_total are equal
(or size_total <= other.size_total).

And of course, if you use std::vector, the compiler generated
assignment operator and copy constructor are sufficient; you
don't have to write anything.

  • Is there any reason why you use a pointer for I1? (Or is
    this just an artifact of a larger context from which you
    extracted the code?)

  • Concerning someFunction( &I2.retGrid() );,
    someClass::retGrid() returns a pointer. Regardless of whether
    you call the function through a pointer or an object. Taking
    the address results in a T**.

  • Concerning the last call, there is nothing that would cause
    a problem here in the code you've shown us. As long as I2 is
    in scope and hasn't deleted it's object, there should be no
    problem. This is the correct way of calling the function on an
    object. The problem in your code is elsewhere.

完美的未来在梦里 2024-11-15 12:02:40

我不确定您收到的运行时错误,但 status = someFunction(&I2.retGrid()); 正在将指针传递给临时对象。

运行时错误可能是由于缺少在 someClass中调用的复制构造函数所致。 I2 = *I1;

I'm not sure of the runtime error that you are getting but status = someFunction(&I2.retGrid()); is passing pointer to a temporary object.

The runtime error could be because of missing copy constructor that is invoked in someClass<double> I2 = *I1;

月亮是我掰弯的 2024-11-15 12:02:40

感谢大家提出的非常有用的评论,特别是 AAT、David Rodriguez - drbeas、James Kanze 和 Marius Bancila 的评论。

事实证明,问题出在 someFunction 内与第三方函数的接口不正确。我在睡眠后发现并修复了错误,现在调用:

status = someFunction(I2.retGrid()); // Compiler gives no error but function returns error value in status

工作正常。

但这次讨论揭示了其他非常重要的相关问题,即与我的复制构造函数和赋值运算符相关的内存管理问题以及建议使用向量。我相信这篇文章在这些优点上有很大的价值。

Thank you to everyone for the extremely useful comments, especially those by AAT, David Rodriguez - dribeas, James Kanze, and Marius Bancila.

It turns out the problem was improper interface with a third-party function inside someFunction. I found and fixed the error after some sleep and now the call:

status = someFunction(I2.retGrid()); // Compiler gives no error but function returns error value in status

works correctly.

But this discussion brought other very important related issues to light, namely the memory management issues related to my copy constructor and assignment operator and suggested use of vectors. I believe this thread has a lot of value on those merits.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文