为用户定义的类正确调用复制构造函数/赋值运算符

Invoking copy constructor/ assignment operator properly for user defined class

提问人:skr 提问时间:10/13/2018 最后编辑:skr 更新时间:10/13/2018 访问量:59

问:

我有一个如下所示的班级:Point

class Point
{
    int x_v = {-1};
    int y_v = {-1};
    int val_v = {0};
    double f_v = {1000000};
    double g_v = {1000000};
    double h_v = {1000000};
    Point* parent_v = nullptr;
public:
    Point(){}
    Point(int x, int y, int val) : x_v{x}, y_v{y}, val_v{val}
    {}
    Point(const Point& p1)
    {
        x_v = p1.x();
        y_v = p1.y();
        val_v = p1.val();
        f_v = p1.f();
        g_v = p1.g();
        h_v = p1.h();
        *(parent_v) = *(p1.parent());
    }
    ~Point(){}

    int val() const
    {
        return val_v;
    }

    int x() const
    {
        return x_v;
    }

    int y() const
    {
        return y_v;
    }

    double f() const
    {
        return f_v;
    }

    double g() const
    {
        return g_v;
    }

    double h() const
    {
        return h_v;
    }

    Point* parent() const
    {
        return parent_v;
    }

    void set_g(double g)
    {
        g_v = g;
        f_v = g_v + h_v;
    }

    void set_h(double h)
    {
        h_v = h;
        f_v = g_v + h_v;
    }

    void set_parent(Point* p)
    {
        parent_v = p;
    }

    Point& operator=(const Point& p1)
    {
        x_v = p1.x();
        y_v = p1.y();
        val_v = p1.val();
        f_v = p1.f();
        g_v = p1.g();
        h_v = p1.h();
        *(parent_v) = *(p1.parent());
        return *this;
    }

    friend bool operator<(const Point& p1, const Point& p2)
    {
        return p1.f() < p2.f();
    }

    friend bool operator==(const Point& p1, const Point& p2)
    {
        std::cout << p1.g() << "\t" << p2.g() << "\n";
        return (p1.x() == p2.x()) && (p1.y() == p2.y()) && (p1.g() == p2.g());
    }

    friend bool operator!=(const Point& p1, const Point& p2)
    {
        return !(p1 == p2);
    }
};

在代码的后半部分,有:

std::set<Point> frontier;
frontier.insert(start_v);
start_v.set_g(0);
std::cout << "start g: " << start_v.g() << "\n";
start_v.set_h(this -> manhattan(start_v));
while(!frontier.empty())
{
    Point curr_point = *(std::min_element(frontier.begin(), frontier.end()));
    std::cout << "curr_point g: " << curr_point.g() << "\n";
    /* Other code */
}

创建复制构造函数和赋值运算符的原因是为了确保上述块的 while 循环内的行: 正常工作。Point curr_point = *(std::min_element(frontier.begin(), frontier.end()));

该类由另一个名为 :PointAstar

class Astar
{
    std::vector<std::vector<Point>> map_v;
    int map_x = {0};
    int map_y = {0};
    Point start_v;
    Point end_v;
    std::vector<Point> path_v;
public:
    Astar(std::vector<std::vector<int>>&, std::pair<int, int>&, std::pair<int, int>&);
    bool is_valid(int, int);
    double manhattan(Point&);
    void search();
    std::vector<Point> path();
};

它的构造函数:

Astar::Astar(std::vector<std::vector<int>>& map, std::pair<int, int>& start, std::pair<int, int>& end)
{
    map_y = map.size();
    if(map_y)
    {
        map_x = map[0].size();
    }
    if(map_x == 0 || map_y == 0)
    {
        throw std::invalid_argument{"The map is invalid!\n"};
    }
    for(int i = 0; i < map_y; i++)
    {
        map_v.push_back(std::vector<Point>(map_x));
        for(int j = 0; j < map_x; j++)
        {
            map_v[i][j] = Point(j, i, map[i][j]);
        }
    }
    start_v = Point(start.second, start.first, map[start.first][start.second]);
    end_v = Point(end.second, end.first, map[end.first][end.second]);
    if(!is_valid(start_v.x(), start_v.y()))
    {
        throw std::out_of_range{"Start point is out of range!\n"};
    }
    if(!is_valid(end_v.x(), end_v.y()))
    {
        throw std::out_of_range{"End point is out of range!\n"};
    }
}

问题是程序在尝试运行时终止。当我运行调试器时,程序终止于以下行:

map_v[i][j] = Point(j, i, map[i][j]);

这是在添加 的复制构造函数和赋值运算符之后开始的。我无法确定此方案中的确切问题。请帮忙。Point

编辑:

自从问题方向改变并且回答了原始问题以来,之前的所有编辑都已被删除。

C++ 复制构造函数 赋值运算符 User-Defined-Types

评论

0赞 KostasRim 10/13/2018
@MatthieuBrucher无论出于何种原因,他都将指针用作私人成员。你肯定不需要构造函数,因为它们执行的是浅层复制。default
0赞 skr 10/13/2018
根据注释,我更改了复制构造函数。但是现在,似乎没有调用复制构造函数。
0赞 KostasRim 10/13/2018
不要通过提出第二个问题来编辑您的答案。重新发布并缩小范围,具体一点。如果您的帖子中有 5 个答案,这意味着需要 5 个人进行相应的编辑
0赞 skr 10/13/2018
好。我会转发。
0赞 KostasRim 10/13/2018
请缩小您的帖子范围,您的代码中有很多东西没有解释性。此外,您的设计不清楚。我之所以这么说,是因为这样做会得到有用的答案。

答:

1赞 KostasRim 10/13/2018 #1

这句话是你麻烦的根源。让我们稍微解析一下。map_v[i][j] = Point(j, i, map[i][j]);

Point(j, i, map[i][j]) Creates a temporary object of type Point 
                       at this point, due to the Point constructor
                       member variable parent_v is nullptr
map_v[i][j] = ....     This uses the overloaded assignment operator. 
                       Go to its definition and at the end you will see 
                       *(parent_v) = *(p1.parent());

所以语句将产生 .取消引用是 UB,希望会出错。p1.parent()nullptr

评论

0赞 Matthieu Brucher 10/13/2018
*(parent_v)根据定义,也将如此。parent_vnullptr
0赞 KostasRim 10/13/2018
@MatthieuBrucher取消引用 a 始终是 UB。nullptr
0赞 skr 10/13/2018
@KostasRim : 请看编辑。似乎没有正确调用复制构造函数。我怎样才能正确处理复制?parent_v
0赞 KostasRim 10/13/2018
@skr_robo它不调用 CCTOR,而是调用重载赋值运算符。无论如何,该问题都会在您的两个构造函数(复制和赋值)中复制。我已经告诉过你,你正在取消引用.我不知道你想实现什么,但如果这是你想要的东西,你可以复制指针(如果你不小心,可能会产生各种问题)nullptr
0赞 Matthieu Brucher 10/13/2018
@KostasRim我不是在说相反的??事实上,默认指针会比我们在这里的指针更好,但稍后会导致段错误,因为指针将悬空,并且在调整向量大小时不会更新。