c ++ возвращает значение при попытке поймать - PullRequest
1 голос
/ 22 ноября 2010

привет, что мне делать, когда ПРЕДУПРЕЖДЕНИЕ "управление достигает конца не пустой функции" происходит? мой перегруженный оператор попытался поймать и 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 ]

8 голосов
/ 22 ноября 2010

Необходимо убедиться, что все пути кода возвращают значение, если функция возвращает что-либо кроме void.

Если вы обрабатываете исключения внутри этой функции без повторного броска, почему бы не просто return *this; в конце функции безоговорочно, а не изнутри блока try?

РЕДАКТИРОВАТЬ: согласно приведенному ниже комментарию @ Mark, простое перемещение оператора return скрывает фатальную ошибку в контексте запрошенной операции и делает библиотеку довольно ненадежной в процессе. Лучше распространять исключение, если именно так вы собираетесь обрабатывать ошибки умножения на месте (что кажется разумным подходом).

4 голосов
/ 22 ноября 2010

Решение вашей проблемы:

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;
        }
4 голосов
/ 22 ноября 2010

В основном я понимаю, что ваш оператор выглядит так:

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

Теперь вопрос в том, какое значение вы возвращаете, когда генерируется исключение (и перехватывается)? В ответ вы ничего не возвращаете, так что должен делать компилятор?

Вам нужно решить, что делать на пути к уловке:

  • либо бросить что-то (возможно, то же исключение, либо другое по вашему вкусу)
  • или return *this, если бы вы могли жить с ошибкой

Но в случае с оператором присваивания я настоятельно рекомендую вам НЕ создавать никаких исключений, что несколько отличается от слепого применения блока try / catch.

EDIT

Гораздо более простой подход к вашей проблеме состоит в том, чтобы сначала проверить, throw ваше исключение (без каких-либо изменений), если оно не совпадает, и затем приступить к работе с кодом, не беспокоясь о возникновении исключения.

Это общий способ развития в стране исключений: сначала делайте то, что может выдать, и тогда вам не придется беспокоиться об исключениях, появляющихся здесь и там.

Также, как замечание, не смей бросать bad_alloc ! Вы не можете слепо выбрать существующее исключение и использовать его для своего собственного удобства: тип исключения переносит значение и bad_alloc означает, что система не смогла выполнить ваш запрос памяти, а не то, что некоторая матричная реализация пошла не так, как надо. .

0 голосов
/ 12 июля 2013

Я не знаю ваш более крупный дизайн, но, как правило, перегруженные операторы никогда не должны иметь сбоев во время выполнения (например, "=", "*" и т. Д. Никогда не должны вызывать исключения). Это потому, что пользователи ожидают, что они будут действовать как +, - и т. Д. для номеров.

Подумайте, как пользователь собирается это называть. Похоже, вы хотите, чтобы они имели что-то вроде:

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 ()', но по крайней мере он был предупрежден. Насколько я знаю, это лучшее, что вы можете сделать, если вам действительно нужно поддерживать матрицы с неизвестным количеством строк и столбцов во время компиляции.

0 голосов
/ 22 ноября 2010

Предупреждение относится к тому факту, что существует неисключительный путь управления из функции, который не имеет оператора возврата.

Имеет ли ваша область действия аналогичный возврат? Если он не должен возвращаться, возможно, вы захотите сбросить его.

...