正在调用boost变量中匹配类型的析构函数
Calling the destructor for matched type in boost-variant
我使用的是boost变量,在变量中切换类型时,我希望确保调用析构函数。以下代码"有效",但我不确定原因。我觉得它应该segfault,因为它在未初始化的指针上调用delete。幕后是否有某种助推变体的魔力?
#include <iostream>
#include <boost/variant.hpp>
using namespace std;
class A
{
public:
A() {}
virtual ~A() { cout << "Destructing A" << endl; }
};
class B
{
public:
B() {}
virtual ~B() { cout << "Destructing B" << endl; }
};
typedef boost::variant<A*, B*> req;
class delete_visitor : public boost::static_visitor<void>
{
public:
inline void operator() (A *a) const
{
cout << "Will destruct A" << endl;
delete a;
}
inline void operator() (B *b) const
{
cout << "Will destruct B" << endl;
delete b;
}
};
class Wrapper
{
public:
Wrapper(int s) {
setBackend(s);
}
virtual ~Wrapper() {
// cleanup
boost::apply_visitor(delete_visitor(), my_pick);
}
void setBackend(int s)
{
// make sure if we already have put something in our variant, we clean it up
boost::apply_visitor(delete_visitor(), my_pick);
if(s == 0)
my_pick = new A();
else
my_pick = new B();
}
private:
req my_pick;
};
int main()
{
Wrapper *w = new Wrapper(0);
w->setBackend(1);
delete w;
return 0;
}
以下是我得到的输出:
Will destruct A
Will destruct A
Destructing A
Will destruct B
Destructing B
根据boost::variant
:的Boost文档
"永不清空"保证
类型变体的所有实例v都保证v已经构造了类型Ti之一的内容,即使对v的操作先前已经失败。
查看"boost/variat.hpp",特别是变体的默认构造函数,您会看到:
// boost/variant.hpp: 1383
variant()
{
// NOTE TO USER :
// Compile error from here indicates that the first bound
// type is not default-constructible, and so variant cannot
// support its own default-construction.
//
new( storage_.address() ) internal_T0();
indicate_which(0); // zero is the index of the first bounded type
}
对于有界的变量类型,第一个类型将获得默认的init。这意味着对于您的req
类型,A *
的init为零。这也意味着B *
是零初始化,因为变量可以被视为一个并集。
在未初始化的指针上调用delete
是Undefined Behavior。它编译的事实并不能使代码合法。无论如何,我认为你应该使用内存管理来处理这种事情:
typedef boost::variant<boost::shared_ptr<A>, boost::shared_ptr<B>> req;
// ....
if (s == 0)
my_pick = boost::make_shared<A>();
else
my_pick = boost::make_shared<B>();
在未初始化的指针上调用delete
是未定义的行为,这意味着任何都可能发生,包括什么都不发生。
特别是如果未初始化的指针正好在以前没有使用过的内存中,那么这个内存不太可能包含零,所以delete会得到一个空指针,什么也不做。
第二个可能的(!)结果是,您得到了预期的segfault,因为指针恰好位于不包含有效指针值的内存中。
其他可能性是:指针恰好位于一个包含完全不相关对象地址的位置,从而破坏该地址(可能是在调用完全错误的析构函数时)。或者指针指向堆,但在中间的某个位置,您将损坏内部堆结构,从而在稍后导致神秘的崩溃。
这份清单绝非详尽无遗。
相关文章:
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 不命名构造函数和析构函数上的类型错误
- C++中的基元类型有析构函数吗?
- LINUX 操作系统上的错误:令牌之前预期的构造函数、析构函数或类型转换'('?
- 显式调用 typedef'd 类类型的析构函数的正式正确方法
- 即使基类和派生类只使用基元数据类型,我是否需要定义虚拟析构函数
- 在从仅移动类型派生的类中定义析构函数在使用 std::vector emplace_back或push_back创建时会
- 当 T 具有非平凡析构函数时,类类型 T 的对象是否可以常量初始化?
- 非默认析构函数会导致不完整的类型错误
- 错误 c++ 在令牌之前'('预期的构造函数、析构函数或类型转换
- 触发的断点(析构函数)与类模板类型是自身的一个版本
- 错误:在“(”标记之前进行预期的构造函数、析构函数或类型转换.即使我有一个构造函数
- GCC 9.1 返回 void& 作为显式析构函数调用的结果类型。这是一个错误吗?
- 获取错误:在“(”标记之前进行预期的构造函数、析构函数或类型转换
- 不是多态类型,或者为什么我们在这里需要虚拟析构函数?
- 如何销毁通过"放置新"构造的无析构函数类型
- C++联合如何知道其中存储的类型以及要调用哪个析构函数
- 错误:令牌之前的预期构造函数、析构函数或类型转换'*'
- 不同的析构函数类型
- 字符串常量之前的预期构造函数、析构函数或类型转换