2011-05-20 37 views
0

我一直在寻找这个问题的解决方案,但似乎找不到一个。我敢肯定,这个一般性问题已前的某个地方有人问,但希望你能与我的具体情况帮...在C++中通过引用传递类成员函数返回值

我有一个类模板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类以外的功能与以下原型PE:

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 

代码编译但是我得到了一个运行时间e rror(来自someFunction内的另一个函数调用的错误状态值)。

如何正确地将I2传递给someFunction

非常感谢......

+2

您需要定义一个拷贝构造函数。 – 2011-05-20 12:31:06

+0

谢谢Neil,我在代码中有一个拷贝构造函数,但是我把它从这篇文章中删除了。我编辑了这篇文章以包含它。 – Evan 2011-05-20 12:36:56

+0

您可以检查I2的内容(例如,将它们转储出来或在调试器中检查)?它是否已从I1正确复制? (我猜测你的“坏状态值”可能反映了以某种方式通过双阵列的内容。) – AAT 2011-05-20 13:00:13

回答

1

通过retGrid返回您正在尝试采取临时对象的地址(在这种情况下,一个指针,但这个并不重要)。因此你不能使用&的方法。

如果没有&符号,您可以将I2的内部数组传递给someFunction。如果这对你来说不好(即因为你得到某种运行时错误),考虑制作一个这个数组的副本并将它传递给someFunction

+0

谢谢Xion ......你有什么建议让副本传递给'someFunction'? – Evan 2011-05-20 12:38:46

+0

@Evan:你不能像这样传递一个原始数组,并且期望在没有某种中间步骤的情况下自动获得一个副本。您可以直接传递您的课程,或者您可以手动复制您的数组并传递副本。 – 2011-05-21 01:40:59

1

当你在你的类中有指针并且你必须为每个对象分配内存时,你需要定义一个拷贝构造函数和一个赋值操作符。您只添加了后面的内容。此初始化

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; 
} 
+0

谢谢马吕斯。我在我的文章中包含了复制构造函数。我原本排除它,但它在我的代码中。 – Evan 2011-05-20 12:39:52

+0

赋值运算符的这种实现是错误的,并且如果表达式'new T [...]'中的任何内容抛出异常(并且您可以'不包括T)排除'bad_alloc'。 – 2011-05-20 13:13:40

+0

是的,当然,但是对于任何类型的内存分配都是一样的 – 2011-05-20 13:48:26

0

我不知道你得到,但status = someFunction(&I2.retGrid());被传递指针的临时对象的运行时错误。

运行时错误可能是因为在someClass<double> I2 = *I1;

1

第一个问题调用缺少拷贝构造函数:你为什么不使用使用std::vector,而不是 试图自己管理的内存。您不显示 析构函数;我想你在那里释放记忆。但也有 仍然存在问题:

  • 在拷贝构造函数,你用memcpy。当您通过double实例化时,这不是问题 ,但对于其他类型,它可能是问题 。您应该使用std::copy

  • 如果您使用std::vectorretGrid仍然需要 回报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在范围 并没有将其删除的对象,应该是没有问题的 。这是在 对象上调用该函数的正确方法。代码中的问题在其他地方。

0

谢谢大家了非常有用的意见,尤其是那些由AAT,大卫·罗德里格斯 - dribeas,詹姆斯甘孜,马吕斯Bancila。

原来的问题是不恰当的接口与内部someFunction第三方功能。我发现并修正了一些睡眠后的错误,现在通话:

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

工作正常。

但是这个讨论带来了其他非常重要的相关问题,以光,即与我的拷贝构造函数和赋值操作符的内存管理问题,并建议使用的载体。我相信这个线程对这些优点有很大的价值。

相关问题