【问题标题】:c++ return value when try and catchc++ 在尝试和捕获时返回值
【发布时间】:2010-11-22 16:20:41
【问题描述】:

嗨,当警告“控制到达非无效函数的结尾”发生时我该怎么办? 我的重载运算符在 try 范围内有 try 和 catch 和 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;
            }
        }

【问题讨论】:

  • 请发布您的代码(以及您使用的编译器)。
  • 您应该修复警告。现在,你有一个例子来说明你的问题吗?
  • 请贴出你的代码,我从你的问题中得到了一个模糊的概念。
  • 你在 catch 范围内返回 smth 吗?
  • 好的,先谢谢了

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


【解决方案1】:

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

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

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

【讨论】:

  • 将 return 放在函数末尾只是隐藏了一个事实,即您根本无法对其进行矩阵乘法的某些输入。如果您正常返回,它看起来好像成功了,但实际上并没有。完全取消 catch 块并让异常传播出去以便可以找到并修复错误代码不是更好吗?
  • @Mark B - 你是对的:我在代码出现之前发布了这个。请注意关于异常处理的警告
  • @Mark 和 Steve,我注释掉了 try,catch。但是我应该在 throw 之后放什么????
  • 通常你会抛出一个来自&lt;stdexcept&gt;的标准异常,或者你自己的从这些类之一派生的自定义异常(不是std::exception)。在这种情况下,invalid_argument 对我来说似乎是合理的。要记住的主要事情是,由您来定义(和测试)您的 API 的错误,以及它的正常返回代码路径和值。
【解决方案2】:

您的问题的解决方案是这样的:

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】:

    基本上我知道您的操作员看起来像:

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

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

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

    • 要么抛出一些东西(也许是相同的异常,或者你喜欢的另一个)
    • return *this,如果你能忍受这个错误

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

    编辑

    解决您的问题的一种更简单的方法是首先检查 throw 您的异常(不修改任何内容)是否不匹配,然后继续执行您的代码,而不必担心会发生异常。

    这是在异常领域开发的一般方式:先做可能抛出的事情,然后您就不必担心到处出现异常。

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

    【讨论】:

    • 您能否详细说明最后一段?这是否意味着我不应该把异常放在首位?
    【解决方案4】:

    警告是指在没有返回语句的函数之外存在非异常控制路径。

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

    【讨论】:

      【解决方案5】:

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

      想想用户将如何称呼它。看起来您希望他们获得以下便利:

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

      现在,如果您确实需要支持在运行时设置大小的矩阵,您将有可能会失败的加、减和乘操作。我个人不会在此类对象上重载实际的运算符 、+、-、= 等,因为您只能在异常情况下发出错误信号。

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

      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()”逻辑,用户将无法得到他所期望的,但至少他已被警告过。据我所知,如果您确实必须在编译时支持具有未知行数和列数的矩阵,那么这是您能做的最好的事情。

      【讨论】:

        猜你喜欢
        • 2016-05-02
        • 2019-04-14
        • 1970-01-01
        • 2016-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-14
        • 1970-01-01
        相关资源
        最近更新 更多