接收并非所有控制路径返回值的警告



我刚刚在对象注射(CPP)中写下了我的第一个微型项目。看来该程序运行良好,但是当我编译时,我会收到以下警告::警告C4715:'Collection :: GetCircleat':并非所有控制路径返回值。我无法理解该警告的原因是什么。

我想添加一些有关我程序的单词:该程序在整数XY平面中输入了一个圆的集合,并检查哪个圆在平面中包含一个给定点。对于那个任务,我使用了课程。班级"点"代表其坐标。类"圆"代表平面上有色圆圈。该类包含"点"类型的变量,该变量代表其圆的中心和半径。该类还包含一个名为" color"的变量(由整数0或2表示,当0表示一个圆圈不包括给出的点,而2表示相反),以及一个检查给定点是否包含的函数在一个圆圈中。最后,我们有"集合"班,代表了一系列圆圈。变量"计数"是圆的数量,变量"圆"是集合中圆圈的指针。此类包含返回包括点的圆圈的函数getCircleat。这就是使警告上述警告的功能。

HIRES是我的代码:

#include <iostream>
using namespace std;
#include "point.h"
#include "circle.h"
#include "collection.h"
int main()
{
Collection g(4, 3, 2, 0);
cout << "-- before setColor(2) --" << endl;
g.print();
Point p(5, 1);
g.getCircleAt(p).setColor(2);
cout << "-- after setColor(2) --" << endl;
g.print();
return 0;
}
#ifndef POINT_H
#define POINT_H
class Point
{
public:
Point(int x, int y);
int getX() const;
int getY() const;
void setX(int x);
void setY(int y);
void print() const;
private:
int x, y;
};
#endif
#ifndef CIRCLE_H
#define CIRCLE_H
#include "point.h"
class Circle
{
public:
Circle(int x, int y, int r, int color);
int getColor() const;
void setColor(int color);
bool contains(const Point &p) const;
void print() const;
private:
const Point center;
int radius, color;
};
#endif
#ifndef COLLECTION_H
#define COLLECTION_H
#include "circle.h"
class Collection
{
public:
Collection(int radius, int width, int height, int color);
~Collection();
Circle& getCircleAt(const Point &p);
void print() const;
private:
int count;
Circle **circles;
};
#endif
#include <iostream>
using namespace std;
#include "point.h"
Point::Point(int x,int y )
{
 setX(x);
 setY(y);
}
void Point::setX(int x)
{
    this->x=x;
}
void Point::setY(int y)
{
    this->y=y;
}
int Point::getX() const 
{
    return x;
} 
int Point::getY() const 
{
    return y;
}
void Point::print() const
{
        cout <<"x="<< this->x <<"  "<<"y" << this->y ;
        cout <<"  ";
#include <iostream>
using namespace std;
#include "circle.h"
Circle::Circle(int x=0,int y=0,int r=0,int color=0):center(x, y),radius(r),color(color)
{  
}
int Circle::getColor() const
{
    return color;
}
void Circle::setColor(int color)
{
    this->color=color;
}
bool Circle::contains(const Point &p) const
{
    int distX, distY;
    distX=p.getX()-center.getX();
    distY=p.getY()-center.getY();
    if ((distX*distX + distY*distY) > (radius*radius))
        return false;
    return true;
}
void Circle::print() const
{  
    cout<<endl<<"the center of the circle is ("<<center.getX()<<" ,"<<center.getY()<<")"<<" radius "<<radius<<" color "<<color<<endl;  
}

#include <iostream>
using namespace std;
#include "collection.h"
Collection::Collection(int radius, int width, int height, int color)   
{
  int i ,j; 
  count=height*width;
  circles=new Circle* [count];
  for(i=0;i<height;i++)
   for(j=0;j<width;j++)
       circles[j+(i*width)]=new Circle (j*2*radius,i*2*radius,radius,color);
}
Collection::~Collection()
{
    delete []circles; 
}
Circle& Collection::getCircleAt(const Point &p)
{
    for(int i=0;i<count;i++)     
        if(circles[i]->contains(p) ) 
          return *(circles)[i];
}
void Collection::print() const 
{
    for (int i=0;i<count;i++)
       circles[i]->print();
}

预期输出是:

-- before setColor(2) --
Circle center=(0,0) radius=4 color=0
Circle center=(8,0) radius=4 color=0
Circle center=(16,0) radius=4 color=0
Circle center=(0,8) radius=4 color=0
Circle center=(8,8) radius=4 color=0
Circle center=(16,8) radius=4 color=0
-- after setColor(2) --
Circle center=(0,0) radius=4 color=0
Circle center=(8,0) radius=4 color=2
Circle center=(16,0) radius=4 color=0
Circle center=(0,8) radius=4 color=0
Circle center=(8,8) radius=4 color=0
Circle center=(16,8) radius=4 color=0

在此代码中:

Circle& Collection::getCircleAt(const Point &p)
{
    for (int i = 0; i < count; i++)
        if (circles[i]->contains(p))
          return *(circles)[i];
}

当没有一个圆圈包含p时,未执行返回语句。这意味着当发生这种情况时,函数的返回值是不确定的。

有几种解决此问题的方法。最简单的是返回指针而不是参考,然后在找不到圆圈时返回nullptr

Circle* Collection::getCircleAt(const Point &p)
{
    for (int i = 0; i < count; i++)     
        if (circles[i]->contains(p)) 
          return circles[i];
    return nullptr;
}

这里建议的另一个解决方案是抛出例外。但是,我不建议这样做,因为例外是 extifialial 案例。getCircleAt()没有在某个给定位置找到一个圆圈,没有什么例外。这是正常的。这不是错误。

更好的解决方案(在我看来)是完全更改API,而是返回圆圈的索引,而不是圆圈本身。当找不到圆时,返回-1:

int Collection::getIndexAt(const Point &p)
{
    for (int i = 0; i < count; i++)     
        if (circles[i]->contains(p)) 
          return i;
    return -1;
}

然后添加operator []超载以通过其索引访问圆圈:

class Collection
{
public:
    // ...
    Circle& operator [](size_t index)
    {
        return *circles[i];
    }
};

然后,该功能的呼叫者需要检查是否找到了圆圈:

auto index = g.getIndexAt(p);
if (index >= 0) {
    g[index].setColor(2);
    cout << "-- after setColor(2) --" << endl;
    g.print();
} else {
    cout << "-- circle not found at position --" << endl;
}

作为旁注,您的Collection驱动器不正确。您没有释放分配的圆圈。您只是释放动态阵列。您需要:

Collection::~Collection()
{
    // Free each circle.
    for (int i = 0; i < count; ++i)
        delete circles[i];
    // Free the array.
    delete[] circles;
}

代码中的另一个(无关)问题是,您在实现构造函数(而不是在声明中)中为Circle::Circle()构造函数提供默认参数值。你应该改变这一点。默认参数应在声明中指定。这样做:

class Circle {
public:
    Circle(int x = 0, int y = 0, int r = 0, int color = 0);

并从实现中删除默认参数值:

Circle::Circle(int x, int y, int r, int color)

此外,除非这是记忆分配和指针的练习,否则您应该切换到std::vector<Circle>,而不是使用newdelete的指针。手动内存管理容易出错。例如,您在上面的Collection驱动器中弄错了,并且正在泄漏内存。使用标准容器(例如vector)将为您负责内存管理。一个好的经验法则是不要使用newdelete,除非您确实必须。

Collection::getCircleAt在所有情况下均不返回。这是不确定的行为,即使没有触发错误,也可能导致一些非常奇怪的行为。具有非void返回类型的函数必须返回每个路径。这在评论中被殴打致死。

尚未涵盖的是如何修复它。

选项1:投掷异常

Circle& Collection::getCircleAt(const Point &p)
{
    for(int i=0;i<count;i++)     
        if(circles[i]->contains(p) ) 
          return *(circles)[i];
    throw std::runtime_error("No circle at P")
}

如果p经常与圆相关,则会造成重大的性能罚款。因为这不是例外的行为。您只想对异常行为使用异常。如果在p上应该有Circle,这是一个罕见且不寻常的事件,当时没有,我们的例外情况。

g.getCircleAt(p).setColor(2);

如果没有Circle,将完全失败,这表明这是一个不错的选择。您可以在此处捕获并处理例外,将其保留在呼叫堆栈上的另一个功能(在Asker的示例中没有任何)或让程序崩溃并收获捆绑的消息,以了解原因。阅读有关异常处理的文本部分以获取更多信息。

如果在p上没有Circle是常规的预期事件,则例外可能是错误的工具。继续进行选项2

选项2:返回金丝雀值

Circle* Collection::getCircleAt(const Point &p)
{
    for(int i=0;i<count;i++)     
        if(circles[i]->contains(p) ) 
          return (circles)[i];
    return nullptr;
}

请注意,返回类型已更改为指针,因此返回零是合法的。即使编译器允许您,也不要将自己返回零参考的位置。无效的引用是一个令人讨厌的惊喜。指针至少给您一些警告,指出无效的方式可能会出现,所以请注意:

g.getCircleAt(p)->setColor(2);

刚刚删除并访问了无效指针。kaboom。如果该程序没有崩溃,并且不必这样做,那么该程序就疯了。您需要做更多。例如,

Circle * c = g.getCircleAt(p)
if (c != nullptr)
{
    c->setColor(2);
}
else
{
    // do error handling
}

您现在必须做所有错误处理的错误,但是您拥有完全控制权,并且知道成本。如果并不重要,请保持冷静并继续下去。如果需要处理,请处理。

选项2A:std::optional

optional正式化了金丝雀值。您可以测试它以确保您得到响应然后继续进行。首先,一些文档:http://en.cppreference.com/w/cpp/utility/optional

optional实际上只是出现在C 17标准修订中。我认为它是在9月或10月进行正式批准的,因此除非您使用最新的编译器,否则它可能无法使用。

实际上,我没有这样的编译器,并且无法提供我已经测试并知道目前可以使用的代码。这就是为什么这是选项2a的原因。您独自与这个。我还没有机会玩它。

最新更新