C++ 中的段错误对在预分配缓冲区中创建的对象调用虚拟方法
嗯...标题有点拗口,但我真的不确定哪一部分引起了问题,我已经运行了很多次,并且无法查明为什么...
这个想法是使单个 Choice 实例能够存储任何一个值 传递到它的模板列表的类型...它有点像一个联合,除了 它跟踪所存储的类型,并认为每种类型的值是不同的,这使其能够绕过联合成员中构造函数的 C++ 约束。
它在某些情况下确实有效,但清理代码似乎存在一些问题。当我开始将此结构与 std::basic_string 或参数列表中传递的类似类型一起使用时,我就开始出现段错误,但我不明白为什么这会导致任何问题。
这对我自己来说是一个实验,但我看不出它为什么不起作用的任何原因(在 g++ 中以 C++0x 模式编译):
// virtual methods should provide a way of "remembering"
// the type stored within the choice at any given time
struct ChoiceValue
{
virtual void del(void* value) = 0;
virtual bool is(int choice) = 0;
};
// Choices are initialized with an instance
// of this structure in their choice buffer
// which should handle the uninitialized case
struct DefaultChoiceValue : public IChoiceValue
{
virtual void del(void* value) {}
virtual bool is(int choice) { return false; }
};
// When a choice is actually initialized with a value
// an instance of this structure (with the appropriate value
// for T and TChoice) is created and stored in the choice
// buffer, allowing it to be cleaned up later (using del())
template<int TChoice, typename T>
struct ChoiceValue
{
virtual void del(void* value) { ((T*)value)->~T(); }
virtual bool is(int choice) { return choice == TChoice; }
};
template<typename ... TAll>
struct Choice
{
};
template<typename T1, typename ... TRest>
struct Choice<T1, TRest...>
{
// these two constants should compute the buffer size needed to store
// the largest possible value for the choice and the actual value
static const int CSize = sizeof(ChoiceValue<0, T1>) > Choice<TRest...>::CSize
? sizeof(ChoiceValue<0, T1>) : Choice<TRest...>::CSize;
static const int VSize = sizeof(T1) > Choice<TRest...>::VSize
? sizeof(T1) : Choice<TRest...>::VSize;
IChoiceValue* _choice;
char* _choiceBuffer;
char* _valueBuffer;
Choice()
{
_choiceBuffer = new char[CSize];
_valueBuffer = new char[VSize];
_choice = new (_choiceBuffer) DefaultChoiceValue();
}
~Choice()
{
_choice->del(_valueBuffer);
delete[] _choiceBuffer;
delete[] _valueBuffer;
}
template<int TChoice, typename T>
T& get()
{
if(_choice->is(TChoice))
return *(T*)_valueBuffer;
else
{
_choice->del(_valueBuffer);
new (_valueBuffer) T();
_choice = new (_choiceBuffer) ChoiceValue<TChoice, T>();
return *(T*)_valueBuffer;
}
}
};
template<typename T1>
struct Choice<T1>
{
// required for the base case of a template
// with one type argument
static const int CSize = sizeof(ChoiceValue<0, T1>) > sizeof(DefaultChoiceValue)
? sizeof(ChoiceValue<0, T1>) : sizeof(DefaultChoiceValue);
static const int VSize = sizeof(T1);
// I have an implementation here as well in my code
// but it is pretty much just a copy of the above code
// used in the multiple types case
};
如果有人能找出我做错了什么,非常感谢:)
Hmm... Title is a bit of a mouthful, but I'm really not sure which part of this is causing issues, I've run through it a ton of times, and can't pinpoint why...
The idea is for a single Choice instance to be able to store any one value of any
of the types passed in to it's template list... It's kind of like a union, except
it keeps track of the type being stored, and considers values of each type to be distinct, which allows it to get around the C++ constraints on constructors in union members.
It does work in some cases, but there seems to be some problems with the cleanup code. I started getting segfaults the second I started using this structure with std::basic_string or similar types passed in the argument list, but I can't see why that would cause any issues.
This is kind of a though experiment for myself, but I can't see any reason why it shouldn't work (compiled in C++0x mode in g++):
// virtual methods should provide a way of "remembering"
// the type stored within the choice at any given time
struct ChoiceValue
{
virtual void del(void* value) = 0;
virtual bool is(int choice) = 0;
};
// Choices are initialized with an instance
// of this structure in their choice buffer
// which should handle the uninitialized case
struct DefaultChoiceValue : public IChoiceValue
{
virtual void del(void* value) {}
virtual bool is(int choice) { return false; }
};
// When a choice is actually initialized with a value
// an instance of this structure (with the appropriate value
// for T and TChoice) is created and stored in the choice
// buffer, allowing it to be cleaned up later (using del())
template<int TChoice, typename T>
struct ChoiceValue
{
virtual void del(void* value) { ((T*)value)->~T(); }
virtual bool is(int choice) { return choice == TChoice; }
};
template<typename ... TAll>
struct Choice
{
};
template<typename T1, typename ... TRest>
struct Choice<T1, TRest...>
{
// these two constants should compute the buffer size needed to store
// the largest possible value for the choice and the actual value
static const int CSize = sizeof(ChoiceValue<0, T1>) > Choice<TRest...>::CSize
? sizeof(ChoiceValue<0, T1>) : Choice<TRest...>::CSize;
static const int VSize = sizeof(T1) > Choice<TRest...>::VSize
? sizeof(T1) : Choice<TRest...>::VSize;
IChoiceValue* _choice;
char* _choiceBuffer;
char* _valueBuffer;
Choice()
{
_choiceBuffer = new char[CSize];
_valueBuffer = new char[VSize];
_choice = new (_choiceBuffer) DefaultChoiceValue();
}
~Choice()
{
_choice->del(_valueBuffer);
delete[] _choiceBuffer;
delete[] _valueBuffer;
}
template<int TChoice, typename T>
T& get()
{
if(_choice->is(TChoice))
return *(T*)_valueBuffer;
else
{
_choice->del(_valueBuffer);
new (_valueBuffer) T();
_choice = new (_choiceBuffer) ChoiceValue<TChoice, T>();
return *(T*)_valueBuffer;
}
}
};
template<typename T1>
struct Choice<T1>
{
// required for the base case of a template
// with one type argument
static const int CSize = sizeof(ChoiceValue<0, T1>) > sizeof(DefaultChoiceValue)
? sizeof(ChoiceValue<0, T1>) : sizeof(DefaultChoiceValue);
static const int VSize = sizeof(T1);
// I have an implementation here as well in my code
// but it is pretty much just a copy of the above code
// used in the multiple types case
};
Thanks a ton if anyone can find out what I'm doing wrong :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您没有发布与实际崩溃相关的任何代码,但我猜测您要么按值返回
Choice<...>
的实例,要么通过某些调用复制构造函数其他方式。由于您没有定义复制构造函数,因此您可能会双重释放使用Choice<...>::Choice
分配的内存。You didn't post any code related to the actual crash, but I'm going to guess that you either return an instance of
Choice<...>
by value or invoke the copy constructor through some other means. Since you didn't define a copy constructor, you are probably double freeing the memory you allocated withChoice<...>::Choice
.