c ++在try和catch时返回值

时间:2010-11-22 16:20:42

标签: c++ exception return-value try-catch

当警告“控制到达无效功能的结束”时,我该怎么办? 我的重载运算符尝试在try范围中捕获returns *this ;

我正在使用Eclipse,G ++是编译器,UBUNTU linux

NNmatrix & operator*=(const NNmatrix<T> &mtrxB)
        {
            // A=2*3 B=3*4  return C=2*4
            const UINT aRows = this->size1();
            const UINT aCols = this->size2();
            const UINT bRows = mtrxB.size1();
            const UINT bCols = mtrxB.size2();
            try
            {
                // if cols of first(this) matrix == rows of second matrix
                if (aCols != bRows) throw bad_alloc();
                const UINT cRows = aRows;// = rows of first matrix
                const UINT cCols = bCols; // = cols of second matrix
                NNmatrix mtrxC(cRows, cCols);
                T val;
                for (UINT i = 0; i < cRows; i++)
                {
                    for (UINT j = 0; j < cCols; j++)
                    {
                        val = 0;
                        for (UINT k = 0; k < bRows; k++)
                        {
                            val += this->matrix.at(i).at(k) * mtrxB.getElement(k, j);
                        }
                        mtrxC.setElement(i, j, val);
                    }
                }
                *this = mtrxC;
                mtrxC.clear();
                return *this;
            }
            catch (exception& e)
            {
                cout<<"Dimension don't match: ("<<aRows<<","<<aCols<<") ("<<bRows<<","<<bCols<<")"<<endl;
            }
        }

5 个答案:

答案 0 :(得分:8)

如果函数返回除void之外的任何内容,则需要确保所有代码路径都返回一个值。

如果您在不重新抛出的情况下在内部处理此函数的异常,为什么不能无条件地在函数末尾return *this;而不是try块内部?

编辑:根据下面的@ Mark的评论,只需移动return语句就会隐藏在请求的操作的上下文中致命的错误,并使该库在此过程中相当不可靠。最好传播异常,如果这是你将如何处理就地乘法错误(这似乎是一种合理的方法)。

答案 1 :(得分:4)

基本上我认为您的运营商看起来像:

Object& operator=(Object const& rhs)
{
  try
  {
    // something
    return *this;
  }
  catch(std::exception& e)
  {
    std::cerr << e.what() << '\n';
  }
}

现在问题是,当抛出(并捕获)异常时,您返回哪个值? 响应是,你没有返回任何东西,那么编译器应该做什么?

你需要决定在捕获路径上做什么:

  • 要么扔东西(也许是同样的例外,或者你喜欢的另一个)
  • return *this如果您能忍受错误

但是对于赋值运算符,我强烈建议您不要抛出任何异常,这与盲目应用try / catch块略有不同。

修改

解决问题的一个更简单的方法是首先检查,throw您的异常(不修改任何内容)如果不匹配,然后执行您的代码而不用担心发生异常。< / p>

这是在异常土地上发展的一般方式:做可能先抛出的东西,然后你不必担心在这里和那里爆发异常。

另外,作为评论,你不敢扔bad_alloc !您不能盲目地选择现有的异常并为了您自己的方便而使用它:异常类型携带含义bad_alloc意味着系统无法满足您的内存请求,而不是某些矩阵实现出了差错。

答案 2 :(得分:4)

问题的解决方案是:

NNmatrix & operator*=(const NNmatrix<T> &mtrxB)
        {
            // A=2*3 B=3*4  return C=2*4
            const UINT aRows = this->size1();
            const UINT aCols = this->size2();
            const UINT bRows = mtrxB.size1();
            const UINT bCols = mtrxB.size2();
            try
            {
                // if cols of first(this) matrix == rows of second matrix
                if (aCols != bRows) throw bad_alloc();
                const UINT cRows = aRows;// = rows of first matrix
                const UINT cCols = bCols; // = cols of second matrix
                NNmatrix mtrxC(cRows, cCols);
                T val;
                for (UINT i = 0; i < cRows; i++)
                {
                    for (UINT j = 0; j < cCols; j++)
                    {
                        val = 0;
                        for (UINT k = 0; k < bRows; k++)
                        {
                            val += this->matrix.at(i).at(k) * mtrxB.getElement(k, j);
                        }
                        mtrxC.setElement(i, j, val);
                    }
                }
                *this = mtrxC;
                mtrxC.clear();
            }
            catch (exception& e)
            {
                cout<<"Dimension don't match: ("<<aRows<<","<<aCols<<") ("<<bRows<<","<<bCols<<")"<<endl;
                // let the exception propagate
                throw;
            }

            // always return *this
            return *this;
        }

答案 3 :(得分:0)

警告指的是函数中没有非异常控制路径,没有返回语句。

您的捕获范围是否有类似的回报?如果它不应该返回,你可能想要重新抛出。

答案 4 :(得分:0)

我不知道你的大型设计,但作为一般规则,重载运算符应该永远不会有运行时故障(例如“=”,“*”等不应该抛出异常)。 这是因为用户期望他们表现得像+, - 等。数字。

考虑一下用户将如何调用它。看起来你希望他们有这样的便利:

NNMatrix<int> matrixA; // Obviously with real assignments...
NNMatrix<int> matrixB;
matrixA *= matrixB;

现在,如果您确实需要支持在运行时设置大小的矩阵,您将会遇到可能失败的Add,Subtract和Multiply操作。我个人不会在这样的对象上重载实际的运算符,+, - , =等,因为你只能用异常来表示错误。

想一想。您要求用户在每次调用矩阵运算符时都有这样的安全性:

try {
   matrixA *= matrixB;
}
catch(bad_alloc& ba) {
   // Handle runtime error
}

现在,有人打算用try-catch包装你的每一个电话的几率是多少?即使他们这样做,也不比使用普通成员函数的替代方案更清晰:

bool NNMatrix<T>::MultiplyBy(const NNMatrix<T>& other);

如果返回false并且在尺寸不匹配时不进行乘法运算,则会获得与之前相同的行为。现在调用者只需要:

if(!matrixA.MultiplyBy(matrixB)) {
   // Handle runtime error
}

这更好,因为如果他们忘记检查返回,这将永远不会导致崩溃。从公共API可以明显看出,用户需要检查错误,并且操作要么完全成功要么失败。它承认仍然不漂亮,如果用户没有“if()”逻辑,用户将无法得到他所期望的,但至少他已被警告过。据我所知,如果您真的必须在编译时支持具有未知#行和列的矩阵,那么这是最好的。