Select a structure containing a string in one distribution

I am working on a program that stores an important data structure as an unstructured line with program-specific delimiters (so we need to go through the line and extract the information we need as we go), and we would like to convert this more structured data type.

In essence, this requires a structure with a field that describes what data the structure contains, and another field is a string with the data itself. The length of the string will always be known during distribution. We determined through testing that doubling the number of distributions needed for each of these data types is an unacceptable cost. Is there a way to allocate memory for the structure and std :: string contained in the structure in one distribution? If we used cstrings, I would just have char * in the structure and point it to the end of the structure after allocating a block large enough for the structure and string, but we would prefer std :: string if possible.

Most of my experience is with C, so please forgive me for displaying C ++ ignorance here.

+5
source share
8 answers

If you have such strict memory needs, then you will have to give up std::string.

The best alternative is to find or write an implementation basic_string_ref(suggestion for the next C ++ standard library) , which is actually just a char * in combination with size. But it has all (non-mutating) functions std::basic_string. Then you use the factory function to allocate the memory you need (your structure size + string data), and then use the new location to initialize basic_string_ref.

Of course, you will also need a custom delete function, since you cannot just pass a pointer to "delete".


basic_string_ref ( typedefs, string_ref), factory /, T, :

template<typename T> T *Create(..., const char *theString, size_t lenstr)
{
  char *memory = new char[sizeof(T) + lenstr + 1];
  memcpy(memory + sizeof(T), theString, lenstr);

  try
  {
    return new(memory) T(..., string_ref(theString, lenstr);
  }
  catch(...)
  {
    delete[] memory;
    throw;
  }
}

template<typename T> T *Create(..., const std::string & theString)
{
  return Create(..., theString.c_str(), theString.length());
}

template<typename T> T *Create(..., const string_ref &theString)
{
  return Create(..., theString.data(), theString.length());
}

template<typename T> void Destroy(T *pValue)
{
  pValue->~T();

  char *memory = reinterpret_cast<char*>(pValue);
  delete[] memory;
}

, . string_ref, .

+1

std::string, , , . C, .

+1

, , , , string , .

, .

  • , . - , , reserve string .
  • , , char C-style. , string, , . , , . , string, , - <algorithm> s.
+1

Variable Sized Struct ++ - , vanilla ++ .

? , , .

+1

, . ++ , " ". , .

 unsigned char *myPool = new unsigned char[10000];
 struct myStruct
 {
    myStruct(char* aSource1, char* aSource2)
    {
        original = new (myPool) string(aSource1); //placement new
        data = new (myPool) string(aSource2); //placement new
    }
    ~myStruct()
    {
        original = NULL; //no deallocation needed
        data = NULL; //no deallocation needed
    }
    string* original;
    string* data;
};

int main()
{
    myStruct* aStruct = new (myPool) myStruct("h1", "h2");

    //  Use the struct

    aStruct = NULL; //  No need to deallocate
    delete [] myPool;

    return 0;
}

[Edit] NicolBolas . , , . , . allocater , fooobar.com/questions/339408/.... allocate

pointer allocate(size_type n, void * = 0) 
{
    // fail if we try to allocate too much
    if((n * sizeof(T))> max_size()) { throw std::bad_alloc(); }

    //T* t = static_cast<T *>(::operator new(n * sizeof(T)));
    T* t = new (/* provide the address of the original character buffer*/) T[n];
    return t;
}

, . . .

+1

C std::string . , , , std::string . , , , , .

class my_class {
    std::string data() const { return self._data; }
    const char* data_as_c_str() const // In case you really need it!
    { return self._data; }
private:
    int _type;
    char _data[1];
};

. : _data , , factory . IIRC, C99 :

struct my_struct {
    int type;
    char data[];
};

++. ( ++ 11?)

, , factory, , factory my_class - . operator= .


, , .

, , , char , . ,

class structured_data_reference {
public:
    structured_data_reference(const char *data):_data(data) {}
    std::string get_first_field() const {
        // Do something interesting with _data to get the first field
    }
private:
    const char *_data;
};

(, - ). (, std::shared_ptr) , .


- std::string, ( ). , .

+1

, . :

, .

1. struct hack ++

  • , ++
  • , .

:

  • private factory

, .

2. struct

:

struct M {
    Kind _kind;
    std::string _data;
};

M . , std::string ( , ).

. () - ... , , CPU.

+1

, , , , - .

, ++ . C-ish ( , ). , , .

std::string, , ?

, , ? (, , , ). ++ 11 . - , .

, :)

: ? , . , / , .

 // assume that !, [, ], $, % etc. are your program defined delims
 const std::string vital = "!id[thisisdata]$[moredata]%[controlblock]%";

 // define a special struct
 enum Type { ... }; 
 struct Info {
     size_t start, end;
     Type type;
     // define appropriate ctors
 };

 // parse the string and return Info obejcts
 std::vector<Info> parse(const std::string& str) {
      std::vector<Info> v;
      // loop through the string looking for delims
      for (size_t b = 0, e = str.size(); b < e; ++b) {
            // on hitting one such delim create an Info
            switch( str[ b ] ) {
                case '%':
                  ... 
                case '$;:    
                // initializing the start and then move until
                // you get the appropriate end delim
            }
            // use push_back/emplace_back to insert this newly
            // created Info object back in the vector
            v.push_back( Info( start, end, kind ) );
      }
      return v;
 }
0

All Articles