开发者

Segfault in C++ calling virtual method on object created in pre-allocated buffer

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 in开发者_开发问答stance 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 :)


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 with Choice<...>::Choice.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜