包含多态对象的向量:静态断言错误
自大学以来没有使用C++后,我试图使用具有两种类型的子对象的向量,而且我显然得到了一些错误。包含多态对象的向量:静态断言错误
最初我使用了一个可以工作的指针向量,但是如果我理解正确,那么在清除时会泄漏内存。
我得到的错误导致我相信它与类中的静态计数器有关(与最后一个成员一起销毁?),但删除并没有解决它。
错误会导致在此,在stl_construct.h:
#if __cplusplus >= 201103L // A deleted destructor is trivial, this ensures we reject such types:
static_assert(is_destructible<_Value_type>::value,
"value type is destructible");
#endif
嗯,好吧,但我的析构函数都明确声明。我记得父类应该使用虚拟析构函数并修复它,但问题依然存在。
将构造函数/析构函数移到公共虚拟父类上不应该(事实上也没有)改变它。
现在我假设我以某种方式滥用向量。这是我的例子:
主:
#include <stdio.h> #include "Foo.h"
#include <iostream>
Bar buildBar();
int main(int argc, char **argv)
{
std::vector<Foo> Foos;
Foos.reserve(1);
Foos.push_back(buildBar());
for (int idx=(0);sizeof(Foos);idx++)
{
try {
std::cout << "x = " << Foos.at(idx).getLoc().at(0);
}
catch (std::exception& e) {
std::cout << idx << ": Index out of range" << std::endl;
}
}
Foos.clear();
return 0;
}
Bar buildBar()
{
Bar* temp = new Bar(5,6);
return *temp;
}
foo.h中,用构造移到头:
#ifndef FOO_H #define FOO_H
#include <vector>
class Foo
{
public:
//int maxoID(){return lastoID;} //0-indexed
/* Other things */
virtual std::vector<int> getLoc(){ return {x_Base,y_Base};}
Foo():
//oID(-1),
x_Base(-1),
y_Base(-1){}
virtual ~Foo(){}
protected:
int x_Base;
int y_Base;
};
class Bar : public Foo
{
public:
Bar(int x1, int y1):
x_End(-1),
y_End(-1)
{
x_Base = x1;
y_Base = y1;
}
~Bar(){}
std::vector<int> getLoc() {return {x_Base,y_Base,x_End,y_End};}
protected:
int x_End;
int y_End;
};
#endif // FOO_H
回答:
首先,良好的对你进行讯问的原始指针的使用!人们往往盲目地使用它们,并最终导致其他问题。
您现在的问题是你有object slicing。当您将Bar
插入vector<Foo>
时,您将失去有关Bar
的重要信息。如果您调用只需要一个Foo
而不是Foo&
或Foo*
的函数,则会发生同样的情况。
根据您的使用,您可以使用std::unique_ptr
,std::shared_ptr
,或std::reference_wrapper
请注意,您可以使用原始指针,他们将不只是自动内存泄漏,但vector
概不负责用于存储器(这是使用智能指针我指出之一的美容)
这是完全可以接受的:
int main() {
Foo* f = new Foo;
{
std::vector<Foo*> v;
v.push_back(f);
} // v goes out of scope and is cleaned up
delete f; // the vector won't have cleaned this up, it's our responsibility
}
使用unique_ptr
取而代之只是使这一整件事情变得更加简单。当然,在这样的光例如原始指针是易于使用,但在较大的程序能失控:
还要注意,并作为@juanchopanza points out in the comments,你buildBar
函数泄漏内存。当你调用
return *temp;
您创建一个副本,你会失去temp
的内存地址,因此无法将其删除。
Bar buildBar() {
Bar* temp = new Bar(5,6);
return *temp;
}
Bar b = buildBar();
Bar* p = &b; // this only reference the copy, b
delete p; // this is bad, this will (double) delete the memory from b, which is not the same as temp.
b
将被清理时自动超出范围(这是坏的,如果你还试图将其删除),但你没有办法删除temp
回答:
欢迎回来到C++!
您不能将派生类型放入基类型的向量中。这些实例只能是基本类型。如果您尝试向此向量添加派生类型,它将只复制派生类的基础部分。
你第一次是对的 - 你需要一个基本指针向量。只要您从矢量中删除指针,就不会泄漏。
但是,这是2017年,我们现在喜欢避免一般的新/删除。所以你可以使用unique_ptr(C++'11)的向量,它在超出范围时自动删除内存。
std::vector<std::unique_ptr<Bar>> v; v.push_back(std::make_unique<Bar>(0, 0));
你也可以使用变种的向量(C++'17),它们是新型的类型安全联合。在元素上
typedef std::variant<Bar, Foo> MyBar std::vector<MyBar> v;
使用std::visit
或std::get
得到它的类型回来。
编辑:下面是一些代码从变体
bool apply(int& i) {
std::cout << "integer: " << i << std::endl;
return true;
}
bool apply(double& d)
{
std::cout << "double: " << d << std::endl;
return true;
}
void test()
{
typedef std::variant<int, double> asdf;
std::vector<asdf> v;
v.push_back(10);
v.push_back(0.5);
auto myLambda = [](auto&& arg) { return apply(arg); }; // use of auto (the 2nd one) is required.
for (auto& elem : v)
{
std::visit(myLambda, elem);
}
}
以上是 包含多态对象的向量:静态断言错误 的全部内容, 来源链接: utcz.com/qa/261041.html