首页 > 解决方案 > 具有不同数据类型的容器:2 种方法,只有一种可以编译。为什么?

问题描述

我有一个问题,希望这里有人可以帮助我理解这个问题。我目前正在尝试构建一个需要不同类型容器的代码。我发现了一个可以正常工作的公式,但只有在开始使用稍微不同但无法编译的公式之后。我不明白为什么。有人可以向我解释为什么以下代码中的版本 1 不能编译,而版本 2 可以吗?

#include <iostream>
#include <vector>
#include <variant>


struct point
{
    double x;
    double y;
};

class segment
{
public:
    segment() 
    {
        P1.x = 0;
        P1.y = 0;

        P2.x = 0;
        P2.y = 0;
    };
    virtual ~segment() {};

    virtual double get_radius() { return 0; };
    virtual double get_length() { return 0; };
    virtual double get_angle() { return 0; };

    int segment_id = 0;

protected:
    point P1;
    point P2;
};

class Line : public segment
{
public:
    Line() {};
    Line(const point pt1, const point pt2)
    {
        P1.x = pt1.x;
        P1.y = pt1.y;

        P2.x = pt2.x;
        P2.y = pt2.y;

        segment_id = 1;
    };

    ~Line() {};

    double get_length() { return calc_length(); };
    double get_angle() { return calc_angle(); };

private:
    double calc_length()
    {
        // calculate length (here: dummy value)
        return 1;
    }

    double calc_angle()
    {
        // calculate angle (here: dummy value)
        return 0.5;
    }

    double length = 0;
    double angle = 0;
}
;

class circle : public segment
{
public:
    circle()
    {
        center.x = 0;
        center.y = 0;
    };
    circle(const double r, const point c)
    {
        radius = r;
        center.x = c.x;
        center.y = c.y;

        segment_id = 2;
    };

    ~circle() {};

    double get_radius() { return radius; };
    point get_center() { return center; };
    double get_length() { return 3.14 * radius; }; //returns circumference

private:
    double radius = 0;
    point center;
};

//-------------------------------------------------------

int main()
{
    int nbr = 5;
    point start;
    start.x = 1;
    start.y = 2;

    point end;
    end.x = 3;
    end.y = 4;

    point c;
    c.x = 0;
    c.y = 0;

    double r = 9;

    circle* myCircle = new circle(r, c);
    Line* myLine = new Line(start, end);
    
    //VERSION 1: Does not compile. I get an exception in <memory> line 1762 when trying to delete _Ptr
    std::vector<std::unique_ptr<segment>> v1;

    v1.emplace_back(myCircle);

    v1.emplace_back(myCircle);

    std::cout << v1[0]->get_radius() << std::endl;

    v1.emplace_back(myLine);

    std::cout << v1[1]->segment_id << std::endl;


    //VERSION 2: Compiles
    std::vector<std::unique_ptr<segment>> v2;

    v2.emplace_back(new circle(r, c));

    std::cout << v2[0]->get_radius() << std::endl;

    v2.emplace_back(new Line(start, end));

    std::cout << v2[1]->segment_id << std::endl;
}

标签: c++typescontainers

解决方案


问题很可能是这样的:

v1.emplace_back(myCircle);

v1.emplace_back(myCircle);

这将创建两个不同std::unique_ptr<segment>>的对象,它们都使用完全相同的指针指向完全​​相同的对象。这打破std::unique_ptr.

当第一个元素被破坏时,第二个元素变得无效,尝试破坏第二个元素将导致未定义的行为

您需要创建两个真正独特的不同对象:

v1.emplace_back(std::make_unique<circle>(r, c));
v1.emplace_back(std::make_unique<circle>(r, c));

如果您只想要一个circle对象并且矢量元素应该共享这个对象,那么std::shared_ptr可能是一个好主意。但是你仍然不能像现在这样创建它,而是必须从第一个元素复制到第二个元素。

也许是这样的:

std::vector<std::shared_ptr<segment>> v1;

v1.emplace_back(std::make_shared<circle>(r, c));
v1.emplace_back(v1[0]);  // Create a shared copy of the first circle element

推荐阅读