C ++中的Segfault调用在预分配缓冲区中创建的对象上的虚拟方法

时间:2010-10-04 21:22:41

标签: c++ templates gcc c++11 placement-new

嗯...标题有点拗口,但我真的不确定这部分是什么导致了问题,我已经经历了很多次,并且无法确定原因......

这个想法是让一个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
};

非常感谢,如果有人能找出我做错了什么:)

1 个答案:

答案 0 :(得分:4)

您没有发布任何与实际崩溃相关的代码,但我猜测您要么按值返回Choice<...>的实例,要么通过其他方式调用复制构造函数。由于您没有定义复制构造函数,因此您可能会将使用Choice<...>::Choice分配的内存双倍释放。