当警告“控制到达无效功能的结束”时,我该怎么办?
我的重载运算符尝试在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;
}
}
答案 0 :(得分:8)
如果函数返回除void
之外的任何内容,则需要确保所有代码路径都返回一个值。
如果您在不重新抛出的情况下在内部处理此函数的异常,为什么不能无条件地在函数末尾return *this;
而不是try
块内部?
答案 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()”逻辑,用户将无法得到他所期望的,但至少他已被警告过。据我所知,如果您真的必须在编译时支持具有未知#行和列的矩阵,那么这是最好的。