Selecting a structure with a variable-length array element

I know I can do new char[n] to create an array of n characters. This works even when n not a compile time constant.

But let's say I need a size variable followed by n characters:

My first attempt is as follows:

 struct Test { std::size_t size; char a[]; }; 

However, it seems that new Test[n] does not do what I expect, and instead allocates n size s.

I also found that sizeof(std::string) is 4 in ideone, so it seems like it can allocate both the size and the char array in one block.

Is there a way to achieve what I described (presumably what std::string already does)?

+7
source share
5 answers

While you can do this (and it has often been used in C as a workaround), this is not recommended. However, if this is really what you want to do ... here is a way to do it with most compilers (including those that don't play well with C99 enhancements).

 #define TEST_SIZE(x) (sizeof(Test) + (sizeof(char) * ((x) - 1))) typedef struct tagTest { size_t size; char a[1]; } Test; int elements = 10; // or however many elements you want Test *myTest = (Test *)malloc(TEST_SIZE(elements)); 

Specifications C through C99 do not allow a zero-length array within the structure. To get around this, an array with one element is created, and one size smaller than the requested number of elements is added to the size of the actual structure (size and first element) to create the estimated size.

+10
source

You can use placement new :

 #include <new> struct Test { size_t size; char a[1]; static Test* create(size_t size) { char* buf = new char[sizeof(Test) + size - 1]; return ::new (buf) Test(size); } Test(size_t s) : size(s) { } void destroy() { delete[] (char*)this; } }; int main(int argc, char* argv[]) { Test* t = Test::create(23); // do whatever you want with t t->destroy(); } 
+8
source

You can also use the "Length 1 Array" trick. This is in C:

 struct Test { size_t size; char a[1]; } int want_len = 2039; struct Test *test = malloc(sizeof(struct Test) + (want_len - 1)); test->size = want_len; 

GCC also supports arrays of "0 length" for this purpose: http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

+6
source

If I understand correctly, you need a class that stores a single pointer to a dynamically allocated string with a length prefix. You can do this by taking advantage of the fact that char* can safely alias something.

The simplest implementation, just to show how this can be done :

 class LPS { private: char* ptr; public: LPS() noexcept : ptr(nullptr) {} // empty string without allocation explicit LPS(std::size_t len) { // Allocate everything in one go // new[] gives storage aligned for objects of the requested size or less ptr = new char[sizeof(std::size_t) + len]; // Alias as size_t // This is fine because size_t and char have standard layout *reinterpret_cast<std::size_t*>(ptr) = len; } explicit LPS(char const* sz) { std::size_t len = std::char_traits<char>::length(sz); ptr = new char[sizeof(std::size_t) + len; *reinterpret_cast<std::size_t*>(ptr) = len; std::copy(sz, sz + len, ptr + sizeof(std::size_t)); } LPS(LPS const& that) { if(that.ptr) { ptr = new char[sizeof(std::size_t) + that.size()]; std::copy(that.ptr, that.ptr + sizeof(std::size_t) + that.size(), ptr); } else ptr = nullptr; } LPS(LPS&& that) noexcept { ptr = that.ptr; that.ptr = nullptr; } LPS& operator=(LPS that) { swap(that); return *this; } ~LPS() noexcept { // deleting a null pointer is harmless, no need to check delete ptr; } void swap(LPS& that) noexcept { std::swap(ptr, that.ptr); } std::size_t size() const noexcept { if(!ptr) return 0; return *reinterpret_cast<std::size_t const*>(ptr); } char* string() noexcept { if(!ptr) return nullptr; // the real string starts after the size prefix return ptr + sizeof(std::size_t); } }; 
+2
source

Suppose that in C ++ they are kept short and clear using std::vector .

 struct Test { std::size_t size; char *a; // Modified to pointer Test( int size ): size(size), a(new char[size+1]) {} }; std::vector<Test> objects(numberOfObjectsRequired,argumentToTheConstructor); 
+1
source

All Articles