c++ - 具有不同数据类型的容器: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;
}
解决方案
问题很可能是这样的:
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
推荐阅读
- windows - 使用 EV 签名证书签署 Windows 驱动程序需要哪些步骤?
- c# - 为什么流利的 Hibernate .Sum 在空表中使用时会抛出 InvalidOperationException?
- python - Discord Webhook 编辑请求返回 400(错误请求)
- python - 如何按四分位数对 pandas 中的值进行分组并获取其他列的指标?
- excel - 单击主工作表上的超链接以过滤第二张工作表上的数据 - Excel VBA
- vue.js - 在 Ionic Vue.js 组件中使用 cordova 插件
- ruby-on-rails - Ruby on Rails,仅在新操作时禁用表单中的文本字段
- express - 将 ServiceMonitor 添加到未在 Prometheus 中注册的现有 Express 微服务中
- swift - 使用 Combine with Swift 异步执行任务
- transcoding - RTPEngine 将 Opus 转码为 PCMU - 无法从默认值更改 Opus 设置